pymc-devs / pymc-devs/pytensor

BUG: pt.roll crashes JAX backend JIT compilation due to dynamic slicing

Open
#1,899 14 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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: main branch
  • 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.