pymc-devs / pymc-devs/pytensor
BUG: pt.roll crashes JAX backend JIT compilation due to dynamic slicing
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 644
- Forks
- 208
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 16
Description
Describe the issue:
When using pt.roll and compiling the graph with the JAX backend (mode="JAX"), compilation fails.
This happens because roll in pytensor/tensor/basic.py is currently implemented as a macro rather than a dedicated Op. It calculates the shift dynamically (shift = shift % _x.shape[axis]), which turns the shift into a symbolic variable. When it subsequently executes the Subtensor slices, JAX encounters dynamic slice indices (JitTracer) instead of static integers and refuses to compile.
Proposed Fix:
To make this compatible with strict JIT backends like JAX (and Numba), we should elevate roll from a macro to a core primitive Op.
If we create a dedicated Roll(Op), the JAX linker can trivially map it to jax.numpy.roll and bypass the dynamic slicing limitation entirely.
I am happy to put together a PR for this if making it a proper Op aligns with the architectural vision.
Reproducable code example:
import pytensor
import pytensor.tensor as pt
x = pt.dmatrix('x')
out = pt.roll(x, shift=2, axis=0)
# Compiles and runs fine in C
f_c = pytensor.function([x], out)
# Crashes in JAX
f_jax = pytensor.function([x], out, mode="JAX")
Error message:
TypeError: Slice entries must be static integers. Got slice(None, JitTracer(int64[]), None) at position 0
Apply node that caused the error: Join(0, Subtensor{start:}.0, Subtensor{:stop}.0)
Toposort index: 5
Inputs types: [TensorType(int8, shape=()), TensorType(float64, shape=(None, None)), TensorType(float64, shape=(None, None))]
PyTensor version information:
- PyTensor Version:
mainbranch - Python Version: 3.14
- Operating system: Linux (Ubuntu)
- How did you install pytensor: conda environment (
pytensor-dev)
Context for the issue:
Any computational graph, model, or downstream library relying on pt.roll currently cannot be compiled using the JAX backend.
Moving this to a primitive Op not only unblocks JAX/Numba compilation but will also clean up the C backend execution by directly mapping to numpy.roll rather than executing split-and-join operations.
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
Start in pytensor/tensor/basic.py at the current roll macro and reproduce the failure with the provided JAX-mode function. Trace how its dynamic slicing reaches the JAX linker; done means pt.roll compiles under JAX while preserving the existing C-backend behavior and supporting the proposed primitive-Op design.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100