pytensor 3.0.1__tar.gz → 3.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytensor-3.0.1/pytensor.egg-info → pytensor-3.1.0}/PKG-INFO +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/_version.py +3 -3
- pytensor-3.1.0/pytensor/assumptions/__init__.py +88 -0
- pytensor-3.1.0/pytensor/assumptions/alloc.py +90 -0
- pytensor-3.1.0/pytensor/assumptions/blockwise.py +17 -0
- pytensor-3.1.0/pytensor/assumptions/core.py +373 -0
- pytensor-3.1.0/pytensor/assumptions/diagonal.py +134 -0
- pytensor-3.1.0/pytensor/assumptions/dimshuffle.py +33 -0
- pytensor-3.1.0/pytensor/assumptions/dot.py +58 -0
- pytensor-3.1.0/pytensor/assumptions/elemwise.py +84 -0
- pytensor-3.1.0/pytensor/assumptions/orthogonal.py +85 -0
- pytensor-3.1.0/pytensor/assumptions/positive_definite.py +167 -0
- pytensor-3.1.0/pytensor/assumptions/reshape.py +28 -0
- pytensor-3.1.0/pytensor/assumptions/shape.py +30 -0
- pytensor-3.1.0/pytensor/assumptions/specify.py +130 -0
- pytensor-3.1.0/pytensor/assumptions/subtensor.py +75 -0
- pytensor-3.1.0/pytensor/assumptions/symmetric.py +118 -0
- pytensor-3.1.0/pytensor/assumptions/triangular.py +167 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/executor.py +16 -25
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/maker.py +0 -19
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/configdefaults.py +2 -9
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/basic.py +1 -2
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/fg.py +13 -7
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/utils.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/linker.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/linker.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/basic.py +1 -1
- pytensor-3.1.0/pytensor/link/numba/dispatch/elemwise.py +948 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/_LAPACK.py +203 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/__init__.py +1 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/dispatch.py +67 -55
- pytensor-3.1.0/pytensor/link/numba/dispatch/linalg/decomposition/svd.py +719 -0
- pytensor-3.1.0/pytensor/link/numba/dispatch/linalg/products.py +330 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/dispatch.py +10 -5
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/scan.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/linker.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/linker.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/utils.py +6 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/printing.py +41 -2
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/basic.py +4 -25
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/loop.py +4 -20
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/op.py +11 -10
- pytensor-3.1.0/pytensor/scan/rewriting/__init__.py +25 -0
- pytensor-3.1.0/pytensor/scan/rewriting/db.py +236 -0
- pytensor-3.1.0/pytensor/scan/rewriting/inplace.py +190 -0
- pytensor-3.1.0/pytensor/scan/rewriting/io.py +291 -0
- pytensor-3.1.0/pytensor/scan/rewriting/merge.py +545 -0
- pytensor-3.1.0/pytensor/scan/rewriting/push_out.py +961 -0
- pytensor-3.1.0/pytensor/scan/rewriting/trace.py +1078 -0
- pytensor-3.1.0/pytensor/scan/rewriting/utils.py +145 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/basic.py +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/basic.py +9 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/extra_ops.py +9 -6
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/svd.py +21 -2
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/products.py +16 -2
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/__init__.py +1 -0
- pytensor-3.1.0/pytensor/tensor/rewriting/assumptions.py +64 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/basic.py +24 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/elemwise.py +38 -47
- pytensor-3.1.0/pytensor/tensor/rewriting/linalg/decomposition.py +494 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/inverse.py +38 -52
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/products.py +75 -3
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/solvers.py +169 -9
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/summary.py +17 -50
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/utils.py +37 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/math.py +42 -3
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/ofg.py +7 -10
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/subtensor.py +912 -203
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/subtensor_lift.py +390 -72
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/special.py +3 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/subtensor.py +105 -5
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/variable.py +4 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/basic.py +3 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/linalg.py +4 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/type.py +10 -0
- {pytensor-3.0.1 → pytensor-3.1.0/pytensor.egg-info}/PKG-INFO +1 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor.egg-info/SOURCES.txt +27 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/scripts/mypy-failing.txt +0 -1
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_printing.py +71 -0
- pytensor-3.0.1/pytensor/link/numba/dispatch/elemwise.py +0 -638
- pytensor-3.0.1/pytensor/scan/rewriting.py +0 -3140
- pytensor-3.0.1/pytensor/tensor/rewriting/linalg/decomposition.py +0 -134
- {pytensor-3.0.1 → pytensor-3.1.0}/LICENSE.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/MANIFEST.in +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/README.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/.templates/PLACEHOLDER +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/.templates/layout.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/.templates/nb-badges.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/.templates/rendered_citation.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/LICENSE.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/README.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/_drafts/benchmark_mlx_v_jax_corrected.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/_thumbnails/autodiff/vector_jacobian_product.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/acknowledgement.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/bcast.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/bcast.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/blog.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/conf.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/core_development_guide.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/css.inc +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/dev_start_guide.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/environment.yml +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/apply.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/apply.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/apply2.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/creating_a_c_op.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/creating_a_numba_jax_op.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/creating_an_op.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/ctype.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/extending_faq.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/extending_pytensor_solution_1.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/graph_rewriting.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/graphstructures.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/inplace.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/op.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/other_ops.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/pics/symbolic_graph_opt.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/pics/symbolic_graph_unopt.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/pipeline.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/scan.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/tips.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/type.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/unittest.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/extending/using_params.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/faq.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/applications/normalizing_flows_in_pytensor.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/autodiff/vector_jacobian_product.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/introduction/pytensor_intro.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/optimize/root.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/page_footer.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/rewrites/graph_rewrites.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/gallery/scan/scan_tutorial.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/generate_dtype_tensor_table.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/glossary.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/Elman_srnn.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/PyTensor.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/PyTensor_RGB.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/PyTensor_logo.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/binder.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/blocksparse.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/colab.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/github.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/lstm.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/lstm_memorycell.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/talk2010.gif +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/images/talk2010.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/install.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/internal/how_to_release.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/internal/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/internal/metadocumentation.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/introduction.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/debugmode.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/function.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/io.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/mode.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/nanguardmode.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/opfromgraph.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/ops.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/profilemode.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/compile/shared.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/config.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/css/d3viz.css +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/js/d3viz.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/mlp.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/mlp.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/mlp2.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/mlp2.pdf +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/mlp2.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/ofg.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/examples/ofg2.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index.ipynb +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index_files/index_10_0.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index_files/index_11_0.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index_files/index_24_0.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/d3viz/index_files/index_25_0.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/features.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/fgraph.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/graph.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/op.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/replace.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/type.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/graph/utils.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/misc/pkl_utils.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/printing.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/scalar/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/scan.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/sparse/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/sparse/sandbox.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/basic.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/basic_opt.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/bcast.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/bcast.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/elemwise.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/extra_ops.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/fft.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/functional.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/io.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/linalg.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/math_opt.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/nlinalg.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/optimize.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/plot_fft.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/random.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/slinalg.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/tensor/utils.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/typed_list.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/index.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/linalg.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/math.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/module_functions.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/random.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/signal.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/library/xtensor/type.md +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/links.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/optimizations.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/pylintrc +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/robots.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/troubleshooting.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/adding.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/adding_solution_1.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/aliasing.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/apply.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/apply.svg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/bcast.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/broadcasting.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/conditions.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/debug_faq.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/dlogistic.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/examples.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/faq_tutorial.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/gradients.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/index.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/loading_and_saving.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/logistic.gp +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/logistic.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/loop.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/loop_solution_1.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/modes.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/modes_solution_1.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/multi_cores.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/nan_tutorial.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/pics/d3viz.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/pics/logreg_pydotprint_predict.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/pics/logreg_pydotprint_prediction.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/pics/logreg_pydotprint_train.png +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/printing_drawing.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/prng.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/profiling.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/profiling_example.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/profiling_example_out.prof +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/shape_info.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/sparse.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/tutorial/symbolic_graphs.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/doc/user_guide.rst +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pyproject.toml +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/_sparse_lazy.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/bin/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/bin/pytensor_cache.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/breakpoint.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/aliasing.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/builders.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/compiledir.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/compilelock.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/debugmode.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/dump.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/monitormode.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/nanguardmode.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/debug/profiling.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/io.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/mode.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/rebuild.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/compile/sharedvalue.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/configparser.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/css/d3viz.css +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/d3viz.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/formatting.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/html/template.html +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/js/d3viz.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/gradient.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/destroyhandler.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/features.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/null_type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/op.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/replace.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/db.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/kanren.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/rewriting/unify.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/traversal.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/graph/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/ifelse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/ipython.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/c_code/lazylinker_c.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/c_code/pytensor_mod_helper.h +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/cmodule.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/cutils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/cvm.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/exceptions.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/interface.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/lazylinker_c.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/op.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/params_type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/c/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/einsum.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/elemwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/extra_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/constructors.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/products.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/solvers.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/linalg/summary.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/pad.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/random.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/scalar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/scan.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/signal/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/signal/conv.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/sort.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/sparse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/subtensor.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/dispatch/tensor_basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/jax/ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/einsum.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/elemwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/extra_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/products.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/solvers.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/linalg/summary.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/pad.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/scalar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/signal/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/signal/conv.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/sort.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/subtensor.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/mlx/dispatch/tensor_basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/cache.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/compile_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/cython_support.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/extra_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/constructors.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/cholesky.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/eigen.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/lu.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/lu_factor.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/qr.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/qz.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/decomposition/schur.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/cholesky.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/general.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/hermitian.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/linear_control.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/lu_solve.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/posdef.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/symmetric.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/triangular.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/tridiagonal.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/solvers/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/summary.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/linalg/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/random.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/scalar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/signal/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/signal/conv.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/sort.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/sparse/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/sparse/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/sparse/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/sparse/variable.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/string_codegen.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/subtensor.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/tensor_basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/typed_list.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/numba/dispatch/vectorize_codegen.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/elemwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/extra_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/linalg/products.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/linalg/summary.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/scalar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/sort.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/pytorch/dispatch/subtensor.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/link/vm.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/check_blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/check_blas_many.sh +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/check_duplicate_key.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/elemwise_openmp_speedup.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/elemwise_time_test.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/frozendict.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/may_share_memory.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/ordered_set.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/misc/pkl_utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/npy_2_compat.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/py.typed +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/raise_op.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/c_code/Faddeeva.cc +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/c_code/Faddeeva.hh +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/c_code/gamma.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/c_code/incbet.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scalar/sharedvar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/checkpoints.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/scan_perform.pyx +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/scan_perform_ext.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/scan/views.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/linalg.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/rewriting.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/sharedvar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/sparse/variable.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/blas_c.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/blas_headers.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/c_code/alt_blas_common.h +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/c_code/alt_blas_template.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/c_code/dimshuffle.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/einsum.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/elemwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/elemwise_cgen.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/exceptions.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/fft.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/fourier.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/functional.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/interpolate.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/_lazy.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/constructors.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/cholesky.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/eigen.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/lu.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/qr.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/decomposition/schur.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/dtype_utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/inverse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/core.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/general.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/linear_control.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/lstsq.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/psd.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/triangular.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/solvers/tridiagonal.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/linalg/summary.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/nlinalg.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/optimize.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/pad.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/op.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/rewriting/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/rewriting/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/rewriting/jax.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/rewriting/numba.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/random/variable.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/reshape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/blas.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/blas_c.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/blockwise.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/einsum.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/extra_ops.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/jax.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/linalg/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/numba.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/optimize.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/reshape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/special.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/rewriting/uncanonicalize.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/sharedvar.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/signal/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/signal/conv.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/slinalg.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/sort.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/symbolic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/type_other.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/var.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/tensor/xlogx.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/typed_list/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/typed_list/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/typed_list/rewriting.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/typed_list/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/indexing.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/random/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/random/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/random/type.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/random/variable.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/reduction.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/__init__.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/indexing.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/math.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/reduction.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/utils.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/rewriting/vectorization.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/shape.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/signal.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor/xtensor/vectorization.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor.egg-info/dependency_links.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor.egg-info/entry_points.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor.egg-info/requires.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/pytensor.egg-info/top_level.txt +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/scripts/slowest_tests/update-slowest-times-issue.sh +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/setup.cfg +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/setup.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/link/c/c_code/test_cenum.h +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/link/c/c_code/test_quadratic_function.c +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_basic.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_breakpoint.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_config.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_gradient.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_ifelse.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_raise_op.py +0 -0
- {pytensor-3.0.1 → pytensor-3.1.0}/tests/test_rop.py +0 -0
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2026-05-
|
|
11
|
+
"date": "2026-05-20T17:31:39-0500",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "3.0
|
|
14
|
+
"full-revisionid": "b712ea6e6a7541ce24c47f8869699178958dadf6",
|
|
15
|
+
"version": "3.1.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Import every rule module so its registrations land on the global registry that
|
|
2
|
+
# ``check_assumption`` consults. The property modules pull in the shared helper
|
|
3
|
+
# modules (alloc, dimshuffle, subtensor, dot, elemwise) transitively.
|
|
4
|
+
import pytensor.assumptions.alloc
|
|
5
|
+
import pytensor.assumptions.blockwise
|
|
6
|
+
import pytensor.assumptions.diagonal
|
|
7
|
+
import pytensor.assumptions.dimshuffle
|
|
8
|
+
import pytensor.assumptions.orthogonal
|
|
9
|
+
import pytensor.assumptions.positive_definite
|
|
10
|
+
import pytensor.assumptions.reshape
|
|
11
|
+
import pytensor.assumptions.shape
|
|
12
|
+
import pytensor.assumptions.subtensor
|
|
13
|
+
import pytensor.assumptions.symmetric
|
|
14
|
+
import pytensor.assumptions.triangular
|
|
15
|
+
from pytensor.assumptions.core import (
|
|
16
|
+
ALL_KEYS,
|
|
17
|
+
DIAGONAL,
|
|
18
|
+
IMPLIES,
|
|
19
|
+
LOWER_TRIANGULAR,
|
|
20
|
+
ORTHOGONAL,
|
|
21
|
+
POSITIVE_DEFINITE,
|
|
22
|
+
SYMMETRIC,
|
|
23
|
+
UPPER_TRIANGULAR,
|
|
24
|
+
AssumptionFeature,
|
|
25
|
+
AssumptionKey,
|
|
26
|
+
ConflictingAssumptionsError,
|
|
27
|
+
FactState,
|
|
28
|
+
check_assumption,
|
|
29
|
+
register_assumption,
|
|
30
|
+
register_constant_inference,
|
|
31
|
+
register_implies,
|
|
32
|
+
)
|
|
33
|
+
from pytensor.assumptions.specify import (
|
|
34
|
+
SpecifyAssumptions,
|
|
35
|
+
assume,
|
|
36
|
+
specify_assumption_rule,
|
|
37
|
+
)
|
|
38
|
+
from pytensor.graph.fg import FunctionGraph
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def summarize_assumptions(feature: AssumptionFeature, var) -> str:
|
|
42
|
+
"""Return a compact ``{...}`` tag of the facts known about *var*.
|
|
43
|
+
|
|
44
|
+
Each TRUE fact appears as its ``short_name``; each FALSE fact as ``!short_name``.
|
|
45
|
+
Implied facts are pruned: a TRUE fact is dropped when a stronger fact (one that
|
|
46
|
+
implies it) is also TRUE, and a FALSE fact is dropped when a weaker fact (one it
|
|
47
|
+
implies) is also FALSE. Return ``""`` when nothing is known.
|
|
48
|
+
"""
|
|
49
|
+
states = {}
|
|
50
|
+
for key in ALL_KEYS:
|
|
51
|
+
try:
|
|
52
|
+
states[key] = feature.get(var, key)
|
|
53
|
+
except ConflictingAssumptionsError:
|
|
54
|
+
states[key] = FactState.CONFLICT
|
|
55
|
+
|
|
56
|
+
tokens = []
|
|
57
|
+
for key in ALL_KEYS:
|
|
58
|
+
state = states[key]
|
|
59
|
+
label = key.short_name or key.name
|
|
60
|
+
if state is FactState.TRUE:
|
|
61
|
+
if any(
|
|
62
|
+
key in weaker and states[stronger] is FactState.TRUE
|
|
63
|
+
for stronger, weaker in IMPLIES.items()
|
|
64
|
+
):
|
|
65
|
+
continue
|
|
66
|
+
tokens.append(label)
|
|
67
|
+
elif state is FactState.FALSE:
|
|
68
|
+
if any(states[w] is FactState.FALSE for w in IMPLIES.get(key, ())):
|
|
69
|
+
continue
|
|
70
|
+
tokens.append(f"!{label}")
|
|
71
|
+
elif state is FactState.CONFLICT:
|
|
72
|
+
tokens.append(f"{label}=CONFLICT")
|
|
73
|
+
|
|
74
|
+
return "{" + ", ".join(tokens) + "}" if tokens else ""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def assumption_tags(outputs) -> dict:
|
|
78
|
+
"""Map each variable reachable from *outputs* to its :func:`summarize_assumptions`
|
|
79
|
+
tag, omitting variables with no known facts."""
|
|
80
|
+
fgraph = FunctionGraph(outputs=list(outputs), clone=False)
|
|
81
|
+
feature = AssumptionFeature()
|
|
82
|
+
fgraph.attach_feature(feature)
|
|
83
|
+
tags = {}
|
|
84
|
+
for var in fgraph.variables:
|
|
85
|
+
tag = summarize_assumptions(feature, var)
|
|
86
|
+
if tag:
|
|
87
|
+
tags[var] = tag
|
|
88
|
+
return tags
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from pytensor.assumptions.core import (
|
|
2
|
+
ALL_KEYS,
|
|
3
|
+
FactState,
|
|
4
|
+
register_assumption,
|
|
5
|
+
true_if,
|
|
6
|
+
)
|
|
7
|
+
from pytensor.tensor.basic import (
|
|
8
|
+
Alloc,
|
|
9
|
+
NotScalarConstantError,
|
|
10
|
+
get_underlying_scalar_constant_value,
|
|
11
|
+
)
|
|
12
|
+
from pytensor.tensor.variable import TensorConstant
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def alloc_of_zero(key, op, feature, fgraph, node, input_states) -> list[FactState]:
|
|
16
|
+
"""``Alloc`` rule for DIAGONAL / LOWER_TRIANGULAR / UPPER_TRIANGULAR: TRUE when
|
|
17
|
+
the fill value is the scalar 0 (an all-zero square matrix), FALSE when it is a
|
|
18
|
+
known non-zero scalar -- the off-diagonal entries are then non-zero, so none of
|
|
19
|
+
these properties holds.
|
|
20
|
+
|
|
21
|
+
Requires the trailing two output dims to be statically known and equal; these
|
|
22
|
+
properties apply only to square matrices. SYMMETRIC uses :func:`alloc_is_symmetric`
|
|
23
|
+
instead, since a constant fill is symmetric whatever its value.
|
|
24
|
+
"""
|
|
25
|
+
out_shape = node.outputs[0].type.shape
|
|
26
|
+
if len(out_shape) < 2:
|
|
27
|
+
return [FactState.UNKNOWN]
|
|
28
|
+
m, n = out_shape[-2], out_shape[-1]
|
|
29
|
+
if m is None or n is None or m != n:
|
|
30
|
+
return [FactState.UNKNOWN]
|
|
31
|
+
try:
|
|
32
|
+
val = get_underlying_scalar_constant_value(node.inputs[0])
|
|
33
|
+
except NotScalarConstantError:
|
|
34
|
+
return [FactState.UNKNOWN]
|
|
35
|
+
return true_if(val == 0, else_false=True)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def alloc_is_symmetric(key, op, feature, fgraph, node, input_states) -> list[FactState]:
|
|
39
|
+
"""``Alloc`` rule for SYMMETRIC: a scalar fill broadcasts one value to every
|
|
40
|
+
entry, so a square output equals its transpose -- whatever the value.
|
|
41
|
+
|
|
42
|
+
A non-scalar fill (e.g. a vector broadcast across rows) is left UNKNOWN.
|
|
43
|
+
"""
|
|
44
|
+
out_shape = node.outputs[0].type.shape
|
|
45
|
+
if len(out_shape) < 2:
|
|
46
|
+
return [FactState.UNKNOWN]
|
|
47
|
+
m, n = out_shape[-2], out_shape[-1]
|
|
48
|
+
if m is None or n is None or m != n:
|
|
49
|
+
return [FactState.UNKNOWN]
|
|
50
|
+
return true_if(node.inputs[0].type.ndim == 0)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def eye_identity_rule(key, op, feature, fgraph, node, input_states) -> list[FactState]:
|
|
54
|
+
"""Rule body: TRUE when an :class:`Eye` node produces the identity matrix (square, k == 0)."""
|
|
55
|
+
n, m, k = node.inputs
|
|
56
|
+
if not isinstance(k, TensorConstant):
|
|
57
|
+
return [FactState.UNKNOWN]
|
|
58
|
+
if k.data.item() != 0:
|
|
59
|
+
# Ones sit on an off-main diagonal, so this is not the identity.
|
|
60
|
+
return [FactState.FALSE]
|
|
61
|
+
if n is m:
|
|
62
|
+
return [FactState.TRUE]
|
|
63
|
+
if isinstance(n, TensorConstant) and isinstance(m, TensorConstant):
|
|
64
|
+
return true_if(n.data.item() == m.data.item(), else_false=True)
|
|
65
|
+
return [FactState.UNKNOWN]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def alloc_diag_at_offset_zero(
|
|
69
|
+
key, op, feature, fgraph, node, input_states
|
|
70
|
+
) -> list[FactState]:
|
|
71
|
+
"""Rule body: TRUE when :class:`AllocDiag` places values on the main diagonal,
|
|
72
|
+
FALSE when it places them on any other diagonal (off-main entries break diagonal /
|
|
73
|
+
symmetric / PD structure regardless of the diagonal vector's values)."""
|
|
74
|
+
return [FactState.TRUE if op.offset == 0 else FactState.FALSE]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def alloc_propagates_matrix_property(
|
|
78
|
+
key, op, feature, fgraph, node, input_states
|
|
79
|
+
) -> list[FactState]:
|
|
80
|
+
"""``Alloc`` broadcasts a value across new or expanded leading axes. When the
|
|
81
|
+
value is already matrix-shaped with non-broadcastable core axes, the alloc
|
|
82
|
+
cannot touch those axes, so the matrix property carries through unchanged."""
|
|
83
|
+
value = node.inputs[0]
|
|
84
|
+
if value.type.ndim >= 2 and not any(value.type.broadcastable[-2:]):
|
|
85
|
+
return [input_states[0]]
|
|
86
|
+
return [FactState.UNKNOWN]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
for _key in ALL_KEYS:
|
|
90
|
+
register_assumption(_key, Alloc)(alloc_propagates_matrix_property)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pytensor.assumptions.core import (
|
|
2
|
+
ALL_KEYS,
|
|
3
|
+
infer_assumption_for_node,
|
|
4
|
+
register_assumption,
|
|
5
|
+
)
|
|
6
|
+
from pytensor.tensor.blockwise import Blockwise
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _blockwise_delegate(key, op, feature, fgraph, node, input_states):
|
|
10
|
+
"""Delegate assumption inference to the ``core_op`` of a Blockwise wrapper."""
|
|
11
|
+
return infer_assumption_for_node(
|
|
12
|
+
key, op.core_op, feature, fgraph, node, input_states
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
for _key in ALL_KEYS:
|
|
17
|
+
register_assumption(_key, Blockwise)(_blockwise_delegate)
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import IntFlag, auto
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pytensor.graph import Apply, FunctionGraph, Op
|
|
8
|
+
from pytensor.graph.features import AlreadyThere, Feature
|
|
9
|
+
from pytensor.graph.traversal import walk_toposort
|
|
10
|
+
from pytensor.tensor.variable import TensorConstant
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FactState(IntFlag):
|
|
14
|
+
"""Three-valued logic for assumption inference.
|
|
15
|
+
|
|
16
|
+
The three fact states are TRUE, FALSE and UNKNOWN.
|
|
17
|
+
|
|
18
|
+
UNKNOWN is the default condition, in which we cannot confirm or deny the fact. TRUE and FALSE are definitive
|
|
19
|
+
states. If we have evidence that a fact is both TRUE and FALSE, we get CONFLICT. In general, a CONFLICT state
|
|
20
|
+
should not be possible.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
UNKNOWN = 0
|
|
24
|
+
TRUE = auto()
|
|
25
|
+
FALSE = auto()
|
|
26
|
+
CONFLICT = TRUE | FALSE
|
|
27
|
+
|
|
28
|
+
def __bool__(self) -> bool:
|
|
29
|
+
raise TypeError(
|
|
30
|
+
"FactState has no boolean value; compare against FactState.TRUE, "
|
|
31
|
+
"FactState.UNKNOWN, etc. explicitly, or use AssumptionFeature.check()."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def join(cls, left: "FactState", right: "FactState") -> "FactState":
|
|
36
|
+
"""Combine two pieces of evidence about the *same* (variable, key)."""
|
|
37
|
+
return cls(left | right)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class AssumptionKey:
|
|
42
|
+
"""Identifies a named structural property (e.g. "diagonal" or "triangular").
|
|
43
|
+
|
|
44
|
+
``short_name`` is an abbreviated label used by ``debugprint(print_assumptions=True)``;
|
|
45
|
+
it falls back to ``name`` when empty.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
short_name: str = ""
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
return self.name
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ConflictingAssumptionsError(ValueError):
|
|
56
|
+
"""Raised when joining evidence about a (variable, key) produces ``FactState.CONFLICT``.
|
|
57
|
+
|
|
58
|
+
Surfaces contradictions between user-asserted facts and inferred facts (or between
|
|
59
|
+
multiple sources of inferred facts) before they can silently corrupt downstream rewrites.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# An inference function takes the active AssumptionKey, the Op, the current AssumptionFeature, the FunctionGraph,
|
|
64
|
+
# the Apply node being analyzed, and the states of the input variables for the current key. It returns a list of
|
|
65
|
+
# FactState with one entry per node output.
|
|
66
|
+
InferFactFn = Callable[
|
|
67
|
+
[AssumptionKey, Op, "AssumptionFeature", FunctionGraph, Apply, list[FactState]],
|
|
68
|
+
list[FactState],
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
# The global inference registry maps (AssumptionKey, Op type) pairs to lists of inference functions.
|
|
72
|
+
# Rules are tried in registration order; the first to return TRUE wins.
|
|
73
|
+
ASSUMPTION_INFER_REGISTRY: dict[tuple[AssumptionKey, type], list[InferFactFn]] = {}
|
|
74
|
+
|
|
75
|
+
# Registry mapping assumptions to other assumptions they imply. For example, a "diagonal" matrix is also "symmetric"
|
|
76
|
+
# and "triangular". This is consulted after all other inference rules to derive additional facts.
|
|
77
|
+
IMPLIES: dict[AssumptionKey, list[AssumptionKey]] = {}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def register_implies(stronger: AssumptionKey, *weaker: AssumptionKey) -> None:
|
|
81
|
+
"""Declare that *stronger* being TRUE implies each *weaker* key is also TRUE."""
|
|
82
|
+
IMPLIES.setdefault(stronger, []).extend(weaker)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Maps a key to a function that infers it directly from a literal TensorConstant's data.
|
|
86
|
+
# AssumptionFeature consults this for variables with no owner, letting a property be
|
|
87
|
+
# derived from raw values (e.g. recognising a constant diagonal matrix).
|
|
88
|
+
ConstantInferFn = Callable[[TensorConstant], FactState]
|
|
89
|
+
CONSTANT_INFER_REGISTRY: dict[AssumptionKey, ConstantInferFn] = {}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def register_constant_inference(key: AssumptionKey, fn: ConstantInferFn) -> None:
|
|
93
|
+
"""Register *fn* as the literal-constant inference for *key*."""
|
|
94
|
+
CONSTANT_INFER_REGISTRY[key] = fn
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# The canonical structural-property keys
|
|
98
|
+
DIAGONAL = AssumptionKey("diagonal", short_name="diag")
|
|
99
|
+
LOWER_TRIANGULAR = AssumptionKey("lower_triangular", short_name="tril")
|
|
100
|
+
UPPER_TRIANGULAR = AssumptionKey("upper_triangular", short_name="triu")
|
|
101
|
+
SYMMETRIC = AssumptionKey("symmetric", short_name="sym")
|
|
102
|
+
POSITIVE_DEFINITE = AssumptionKey("positive_definite", short_name="pd")
|
|
103
|
+
ORTHOGONAL = AssumptionKey("orthogonal", short_name="orth")
|
|
104
|
+
|
|
105
|
+
ALL_KEYS = (
|
|
106
|
+
DIAGONAL,
|
|
107
|
+
LOWER_TRIANGULAR,
|
|
108
|
+
UPPER_TRIANGULAR,
|
|
109
|
+
SYMMETRIC,
|
|
110
|
+
POSITIVE_DEFINITE,
|
|
111
|
+
ORTHOGONAL,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Implications about structural properties derivably from other structural properties
|
|
115
|
+
register_implies(DIAGONAL, LOWER_TRIANGULAR, UPPER_TRIANGULAR, SYMMETRIC)
|
|
116
|
+
register_implies(POSITIVE_DEFINITE, SYMMETRIC)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def register_assumption(
|
|
120
|
+
key: AssumptionKey, *op_types: type
|
|
121
|
+
) -> Callable[[InferFactFn], InferFactFn]:
|
|
122
|
+
"""Decorator that registers an inference rule for ``(key, op_type)`` pairs.
|
|
123
|
+
|
|
124
|
+
The decorated function is called as ``fn(key, op, feature, fgraph, node, input_states)``
|
|
125
|
+
and must return a list of :class:`FactState` with one entry per node output.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def decorator(fn: InferFactFn) -> InferFactFn:
|
|
129
|
+
for op_type in op_types:
|
|
130
|
+
ASSUMPTION_INFER_REGISTRY.setdefault((key, op_type), []).append(fn)
|
|
131
|
+
return fn
|
|
132
|
+
|
|
133
|
+
return decorator
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def infer_assumption_for_node(
|
|
137
|
+
key: AssumptionKey,
|
|
138
|
+
op: Op,
|
|
139
|
+
feature: "AssumptionFeature",
|
|
140
|
+
fgraph: FunctionGraph,
|
|
141
|
+
node: Apply,
|
|
142
|
+
input_states: list[FactState],
|
|
143
|
+
) -> list[FactState]:
|
|
144
|
+
"""Determine the *key* fact for every output of *node*.
|
|
145
|
+
|
|
146
|
+
Walks the Op's MRO for the most specific :func:`register_assumption` rule and
|
|
147
|
+
returns the first non-UNKNOWN result. Falls back to ``UNKNOWN`` per output.
|
|
148
|
+
"""
|
|
149
|
+
rules: list[InferFactFn] = []
|
|
150
|
+
for cls in type(op).__mro__:
|
|
151
|
+
fns = ASSUMPTION_INFER_REGISTRY.get((key, cls))
|
|
152
|
+
if fns is not None:
|
|
153
|
+
rules = fns
|
|
154
|
+
break
|
|
155
|
+
|
|
156
|
+
n_outputs = len(node.outputs)
|
|
157
|
+
for fn in rules:
|
|
158
|
+
output_states = fn(key, op, feature, fgraph, node, input_states)
|
|
159
|
+
if len(output_states) != n_outputs:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
f"an assumption rule returned {len(output_states)} states for "
|
|
162
|
+
f"{n_outputs} outputs on node {node!r}"
|
|
163
|
+
)
|
|
164
|
+
if any(s is not FactState.UNKNOWN for s in output_states):
|
|
165
|
+
return output_states
|
|
166
|
+
|
|
167
|
+
return [FactState.UNKNOWN] * n_outputs
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class AssumptionFeature(Feature):
|
|
171
|
+
"""``FunctionGraph`` feature that tracks symbolic assumptions about variables.
|
|
172
|
+
|
|
173
|
+
Assumptions (e.g. "this matrix is diagonal") are represented as ``(variable,
|
|
174
|
+
AssumptionKey) -> FactState`` mappings. Facts are inferred lazily via per-Op
|
|
175
|
+
rules registered with :func:`register_assumption`.
|
|
176
|
+
|
|
177
|
+
Attached lazily by :func:`check_assumption` on first use.
|
|
178
|
+
Results are cached and automatically refreshed when the graph changes.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
__slots__ = ("_stale_vars", "_var_to_keys", "cache", "fgraph")
|
|
182
|
+
|
|
183
|
+
def on_attach(self, fgraph: Any) -> None:
|
|
184
|
+
if hasattr(fgraph, "assumption_feature"):
|
|
185
|
+
raise AlreadyThere("AssumptionFeature is already attached")
|
|
186
|
+
self.fgraph = fgraph
|
|
187
|
+
self.cache: dict[tuple[Any, AssumptionKey], FactState] = {}
|
|
188
|
+
self._var_to_keys: dict[Any, set[AssumptionKey]] = {}
|
|
189
|
+
self._stale_vars: set = set()
|
|
190
|
+
fgraph.assumption_feature = self
|
|
191
|
+
|
|
192
|
+
def on_detach(self, fgraph: Any) -> None:
|
|
193
|
+
self.cache = {}
|
|
194
|
+
self._var_to_keys = {}
|
|
195
|
+
self._stale_vars = set()
|
|
196
|
+
self.fgraph = None
|
|
197
|
+
del fgraph.assumption_feature
|
|
198
|
+
|
|
199
|
+
def on_change_input(self, fgraph, node, i, old_var, new_var, reason=None) -> None:
|
|
200
|
+
# Carry non-UNKNOWN facts from old_var to new_var, then defer downstream
|
|
201
|
+
# UNKNOWN invalidation to the next get()/check() call.
|
|
202
|
+
# CONFLICT is cached, not raised: the graph mutation has already landed,
|
|
203
|
+
# so raising here corrupts the caller's view.
|
|
204
|
+
for key in self._var_to_keys.get(old_var, ()):
|
|
205
|
+
old_state = self.cache.get((old_var, key))
|
|
206
|
+
if old_state is None or old_state is FactState.UNKNOWN:
|
|
207
|
+
continue
|
|
208
|
+
new_state = self.cache.get((new_var, key))
|
|
209
|
+
if new_state is None or new_state is FactState.UNKNOWN:
|
|
210
|
+
self.cache[(new_var, key)] = old_state
|
|
211
|
+
else:
|
|
212
|
+
self.cache[(new_var, key)] = FactState.join(old_state, new_state)
|
|
213
|
+
self._var_to_keys.setdefault(new_var, set()).add(key)
|
|
214
|
+
|
|
215
|
+
self._stale_vars.update(node.outputs)
|
|
216
|
+
|
|
217
|
+
def on_prune(self, fgraph, node, reason=None) -> None:
|
|
218
|
+
self._stale_vars.difference_update(node.outputs)
|
|
219
|
+
|
|
220
|
+
def clone(self) -> "AssumptionFeature":
|
|
221
|
+
# Cache entries are keyed on variable identity, so the cloned feature starts empty
|
|
222
|
+
# and re-derives facts from the cloned graph (assumptions attached via ``assume()``
|
|
223
|
+
# follow their variables through the clone since they live as graph nodes).
|
|
224
|
+
return AssumptionFeature()
|
|
225
|
+
|
|
226
|
+
def get(self, var: Any, key: AssumptionKey) -> FactState:
|
|
227
|
+
"""Return the inferred :class:`FactState` for ``(var, key)``.
|
|
228
|
+
|
|
229
|
+
Raise :class:`ConflictingAssumptionsError` when the cached state is
|
|
230
|
+
:attr:`FactState.CONFLICT` — surfaces conflicts from substitutions or
|
|
231
|
+
owner-inferred rules at the point of query, where the graph is stable
|
|
232
|
+
and the caller can react.
|
|
233
|
+
"""
|
|
234
|
+
cache_key = (var, key)
|
|
235
|
+
state = self.cache.get(cache_key)
|
|
236
|
+
if state is None or state is FactState.UNKNOWN:
|
|
237
|
+
if self._stale_vars:
|
|
238
|
+
self._drop_unknown_downstream(self._stale_vars)
|
|
239
|
+
self._stale_vars.clear()
|
|
240
|
+
# Re-check: the UNKNOWN will still be valid
|
|
241
|
+
# if the stale vars were not ancestors of var.
|
|
242
|
+
state = self.cache.get(cache_key)
|
|
243
|
+
if state is None:
|
|
244
|
+
state = self._compute(var, key)
|
|
245
|
+
if state is FactState.CONFLICT:
|
|
246
|
+
raise ConflictingAssumptionsError(
|
|
247
|
+
f"Conflicting evidence for key {key!r} on {var!r}."
|
|
248
|
+
)
|
|
249
|
+
return state
|
|
250
|
+
|
|
251
|
+
def check(self, var: Any, key: AssumptionKey) -> bool:
|
|
252
|
+
"""Return ``True`` iff the assumption is definitively TRUE for ``var``."""
|
|
253
|
+
return self.get(var, key) is FactState.TRUE
|
|
254
|
+
|
|
255
|
+
def _compute(self, var: Any, key: AssumptionKey) -> FactState:
|
|
256
|
+
"""Infer the fact state for ``(var, key)``, caching ancestors inputs-first.
|
|
257
|
+
|
|
258
|
+
After owner-based inference, walks the ``IMPLIES`` graph in both directions:
|
|
259
|
+
- Forward: a stronger key being TRUE makes this (weaker) key TRUE.
|
|
260
|
+
- Contrapositive: a weaker key being FALSE makes this (stronger) key FALSE.
|
|
261
|
+
|
|
262
|
+
Raise :class:`ConflictingAssumptionsError` if owner-inferred rules produce
|
|
263
|
+
``FactState.CONFLICT``.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
def deps(v: Any) -> tuple:
|
|
267
|
+
# Stop descending at cached variables — their facts (and their ancestors')
|
|
268
|
+
# are already settled for this key.
|
|
269
|
+
if (v, key) in self.cache:
|
|
270
|
+
return ()
|
|
271
|
+
owner = getattr(v, "owner", None)
|
|
272
|
+
return tuple(owner.inputs) if owner is not None else ()
|
|
273
|
+
|
|
274
|
+
for v in walk_toposort([var], deps):
|
|
275
|
+
if (v, key) in self.cache:
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
# Cache UNKNOWN up front so any recursive ``self.get(v, other_key)`` triggered
|
|
279
|
+
# by the IMPLIES checks sees a placeholder instead of recursing back here.
|
|
280
|
+
self.cache[(v, key)] = FactState.UNKNOWN
|
|
281
|
+
self._var_to_keys.setdefault(v, set()).add(key)
|
|
282
|
+
|
|
283
|
+
owner = getattr(v, "owner", None)
|
|
284
|
+
if owner is not None:
|
|
285
|
+
input_states = [self.get(inp, key) for inp in owner.inputs]
|
|
286
|
+
output_states = infer_assumption_for_node(
|
|
287
|
+
key, owner.op, self, self.fgraph, owner, input_states
|
|
288
|
+
)
|
|
289
|
+
state = output_states[owner.outputs.index(v)]
|
|
290
|
+
elif isinstance(v, TensorConstant) and key in CONSTANT_INFER_REGISTRY:
|
|
291
|
+
state = CONSTANT_INFER_REGISTRY[key](v)
|
|
292
|
+
else:
|
|
293
|
+
state = FactState.UNKNOWN
|
|
294
|
+
|
|
295
|
+
if state is FactState.UNKNOWN:
|
|
296
|
+
for stronger, weaker_list in IMPLIES.items():
|
|
297
|
+
if key in weaker_list and self.get(v, stronger) is FactState.TRUE:
|
|
298
|
+
state = FactState.TRUE
|
|
299
|
+
break
|
|
300
|
+
|
|
301
|
+
if state is FactState.UNKNOWN:
|
|
302
|
+
for weaker in IMPLIES.get(key, ()):
|
|
303
|
+
if self.get(v, weaker) is FactState.FALSE:
|
|
304
|
+
state = FactState.FALSE
|
|
305
|
+
break
|
|
306
|
+
|
|
307
|
+
if state is FactState.CONFLICT:
|
|
308
|
+
raise ConflictingAssumptionsError(
|
|
309
|
+
f"Conflicting evidence for {key} on {v!r} from owner-inferred rules."
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
self.cache[(v, key)] = state
|
|
313
|
+
|
|
314
|
+
return self.cache[(var, key)]
|
|
315
|
+
|
|
316
|
+
def _drop_unknown_downstream(self, start_vars) -> None:
|
|
317
|
+
"""Drop UNKNOWN entries for *start_vars* and downstream so they re-probe."""
|
|
318
|
+
cache = self.cache
|
|
319
|
+
var_to_keys = self._var_to_keys
|
|
320
|
+
clients = self.fgraph.clients
|
|
321
|
+
queue = deque(start_vars)
|
|
322
|
+
seen = set(start_vars)
|
|
323
|
+
while queue:
|
|
324
|
+
var = queue.popleft()
|
|
325
|
+
keys = var_to_keys.get(var)
|
|
326
|
+
if keys:
|
|
327
|
+
for key in [
|
|
328
|
+
k for k in keys if cache.get((var, k)) is FactState.UNKNOWN
|
|
329
|
+
]:
|
|
330
|
+
cache.pop((var, key), None)
|
|
331
|
+
keys.discard(key)
|
|
332
|
+
if not keys:
|
|
333
|
+
var_to_keys.pop(var, None)
|
|
334
|
+
for client_node, _ in clients.get(var, ()):
|
|
335
|
+
for out in client_node.outputs:
|
|
336
|
+
if out not in seen:
|
|
337
|
+
seen.add(out)
|
|
338
|
+
queue.append(out)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def true_if(cond: bool, else_false: bool = False) -> list[FactState]:
|
|
342
|
+
"""``[TRUE]`` when *cond* holds, ``[UNKNOWN]`` (or ``[FALSE]``) otherwise."""
|
|
343
|
+
if cond:
|
|
344
|
+
return [FactState.TRUE]
|
|
345
|
+
return [FactState.FALSE] if else_false else [FactState.UNKNOWN]
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def propagate_first(key, op, feature, fgraph, node, input_states) -> list[FactState]:
|
|
349
|
+
"""Output inherits the assumption iff the first input has it."""
|
|
350
|
+
return true_if(input_states[0] is FactState.TRUE)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def all_inputs_have_key(
|
|
354
|
+
key, op, feature, fgraph, node, input_states
|
|
355
|
+
) -> list[FactState]:
|
|
356
|
+
"""Output inherits the assumption iff *every* input has it."""
|
|
357
|
+
return true_if(all(s is FactState.TRUE for s in input_states))
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def check_assumption(
|
|
361
|
+
fgraph: FunctionGraph | None, var: Any, key: AssumptionKey
|
|
362
|
+
) -> bool:
|
|
363
|
+
"""Return True iff *key* is definitively TRUE for *var* in *fgraph*.
|
|
364
|
+
|
|
365
|
+
Lazily attaches :class:`AssumptionFeature` to *fgraph* if it is not already present.
|
|
366
|
+
"""
|
|
367
|
+
if fgraph is None:
|
|
368
|
+
return False
|
|
369
|
+
feature = getattr(fgraph, "assumption_feature", None)
|
|
370
|
+
if feature is None:
|
|
371
|
+
feature = AssumptionFeature()
|
|
372
|
+
fgraph.attach_feature(feature)
|
|
373
|
+
return feature.check(var, key)
|