Skip to content

Commit 10e5c92

Browse files
committed
JAX Scan: Fix bug when recurring trace matches final requested size
1 parent 25e41c3 commit 10e5c92

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

pytensor/link/jax/dispatch/scan.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
@jax_funcify.register(Scan)
13-
def jax_funcify_Scan(op: Scan, **kwargs):
13+
def jax_funcify_Scan(op: Scan, node, **kwargs):
1414
# Note: This implementation is different from the internal PyTensor Scan op.
1515
# In particular, we don't make use of the provided buffers for recurring outputs (MIT-SOT, SIT-SOT)
1616
# These buffers include the initial state and enough space to store as many intermediate results as needed.
@@ -219,6 +219,8 @@ def get_partial_traces(traces):
219219
if trace.shape[0] > buffer_size:
220220
# Trace is longer than buffer, keep just the last `buffer.shape[0]` entries
221221
partial_trace = trace[-buffer_size:]
222+
elif trace.shape[0] == buffer_size:
223+
partial_trace = trace
222224
else:
223225
# Trace is shorter than buffer, this happens when we keep the initial_state
224226
if init_state.ndim < buffer.ndim:

tests/link/jax/test_scan.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
from pytensor.graph import Apply, Op
1111
from pytensor.scan import until
1212
from pytensor.scan.basic import scan
13-
from pytensor.scan.op import Scan
14-
from pytensor.tensor import random
13+
from pytensor.scan.op import Scan, ScanInfo
14+
from pytensor.tensor import as_tensor, empty, random
1515
from pytensor.tensor.math import gammaln, log
1616
from pytensor.tensor.type import dmatrix, dvector, matrix, scalar, vector
1717
from tests.link.jax.test_basic import compare_jax_and_py
@@ -631,3 +631,37 @@ def block_until_ready(*inputs, jax_fn=jax_fn):
631631

632632
def test_higher_order_derivatives():
633633
ScanCompatibilityTests.check_higher_order_derivative(mode="JAX")
634+
635+
636+
def test_trace_truncation_regression_bug():
637+
# Regression bug for a case where the final recurring trace size matched exactly with the number of steps
638+
n_steps = as_tensor(7, dtype=int)
639+
x0 = scalar("x0")
640+
x0_buffer = empty((n_steps,))[0].set(x0)
641+
642+
# I don't know how to create such a Scan naturally, so we use the internal API
643+
xtm1 = x0.type()
644+
scan_op = Scan(
645+
inputs=[xtm1],
646+
outputs=[xtm1 + 1],
647+
info=ScanInfo(
648+
n_seqs=0,
649+
mit_mot_in_slices=(),
650+
mit_mot_out_slices=(),
651+
mit_sot_in_slices=(),
652+
sit_sot_in_slices=((-1,),),
653+
n_nit_sot=0,
654+
n_untraced_sit_sot_outs=0,
655+
n_non_seqs=0,
656+
as_while=False,
657+
),
658+
)
659+
660+
xs_with_x0 = scan_op(n_steps, x0_buffer)
661+
662+
compare_jax_and_py(
663+
[x0],
664+
[xs_with_x0],
665+
[np.array(0)],
666+
jax_mode="JAX",
667+
)

0 commit comments

Comments
 (0)