|
10 | 10 | from pytensor.graph import Apply, Op |
11 | 11 | from pytensor.scan import until |
12 | 12 | 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 |
15 | 15 | from pytensor.tensor.math import gammaln, log |
16 | 16 | from pytensor.tensor.type import dmatrix, dvector, matrix, scalar, vector |
17 | 17 | from tests.link.jax.test_basic import compare_jax_and_py |
@@ -631,3 +631,37 @@ def block_until_ready(*inputs, jax_fn=jax_fn): |
631 | 631 |
|
632 | 632 | def test_higher_order_derivatives(): |
633 | 633 | 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