pymc-devs / pymc-devs/pytensor
Consider lifting Subtensor through Joins
Open
Nobody has claimed this yet.
graph rewriting
- Dominant language
- Python
- Stars
- 644
- Forks
- 208
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 16
Description
Description
Some example rewrite code
@node_rewriter([Subtensor])
def local_subtensor_of_join(fgraph, node):
"""Lift a Subtensor through a Join.
join(axis=1, x, y)[0] -> join(axis=0, x[0], y[0])
join(axis=0, x, y, z, w)[2] -> z[0]
"""
join_var, *idx = node.inputs
if not (join_var.owner and isinstance(join_var.owner.op, Join)):
return None
join_axis, *join_components = join_var.owner.inputs
# Rewrite only works when the join axis is a constant
if not isinstance(join_axis, Constant):
return None
axis = normalize_axis_index(join_axis.data, join_components[0].type.ndim)
idx_tuple = indices_from_subtensor(idx, node.op.idx_list)
if _axis_is_indexed_by_basic_index(idx_tuple, axis):
# In this case we lift if we have to figure out which component is selected
# by the index along axis
axis_index = idx_tuple[axis]
if isinstance(axis_index, slice):
# This isn't too hard to support, but it's not implemented yet
return None
if not isinstance(axis_index, Constant):
return None
axis_index = axis_index.data.item()
if axis_index < 0:
return None # TODO: Just have to iterate from right to left
for indexed_component in join_components:
component_axis_length = indexed_component.type.shape[axis]
if component_axis_length is None:
# We can't figure out if this component or a later one will be indexed
return None
if axis_index >= component_axis_length:
# Axis index is beyond this component
axis_index -= component_axis_length
else:
# This is the indexed component
break
else: # no-break:
return
out = indexed_component[(*idx_tuple[:axis], axis_index, *idx_tuple[axis + 1 :])]
else:
# Indexing does not acto on axis, we can simply lift through which component
# and join again
indexed_components = [component[idx_tuple] for component in join_components]
new_axis = axis - _ndim_dropped_left_of_axis_by_basic_index(idx_tuple, axis)
out = join(new_axis, *indexed_components)
return [out]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names no files or tests; begin by locating the node_rewriter entry point for Subtensor and the Join, indices_from_subtensor, and axis helper logic shown. Done means the demonstrated indexed and non-indexed-axis Join cases are supported and covered by the relevant rewrite tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100