pytensor 3.1.3__tar.gz → 3.2.1__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.1.3/pytensor.egg-info → pytensor-3.2.1}/PKG-INFO +7 -5
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/creating_a_c_op.rst +0 -316
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/graph_rewriting.rst +7 -222
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/index.rst +1 -0
- pytensor-3.2.1/doc/extending/unification_kanren.rst +250 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/sparse/index.rst +0 -2
- {pytensor-3.1.3 → pytensor-3.2.1}/pyproject.toml +8 -5
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/_version.py +3 -3
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/builders.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/mode.py +3 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/configdefaults.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/features.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/rewriting/basic.py +53 -38
- pytensor-3.2.1/pytensor/graph/rewriting/kanren.py +329 -0
- pytensor-3.2.1/pytensor/graph/rewriting/unify.py +593 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/utils.py +6 -4
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/basic.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/cmodule.py +4 -4
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/op.py +11 -13
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/subtensor.py +1 -5
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/tensor_basic.py +4 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/linker.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/subtensor.py +3 -7
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/__init__.py +3 -0
- pytensor-3.2.1/pytensor/link/numba/dispatch/_llvmlite_self_ref.py +66 -0
- pytensor-3.2.1/pytensor/link/numba/dispatch/_patch_pointer_add.py +37 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/blockwise.py +2 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/elemwise.py +227 -31
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/random.py +2 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/subtensor.py +5 -15
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/vectorize_codegen.py +137 -46
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/subtensor.py +10 -8
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/basic.py +0 -145
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/c_code/gamma.c +0 -16
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/math.py +0 -64
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/__init__.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/basic.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/inner_graph.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/trace.py +1 -1
- pytensor-3.2.1/pytensor/sparse/__init__.py +5 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/basic.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/math.py +33 -6
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/basic.py +1 -8
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/elemwise.py +95 -20
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/extra_ops.py +3 -3
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/math.py +66 -63
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/rewriting/basic.py +1 -2
- pytensor-3.1.3/pytensor/tensor/rewriting/indexed_elemwise.py → pytensor-3.2.1/pytensor/tensor/rewriting/fused_elemwise.py +263 -229
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/math.py +230 -110
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/numba.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/shape.py +1 -2
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/special.py +1 -3
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/subtensor.py +54 -272
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/subtensor_lift.py +15 -8
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/subtensor.py +288 -470
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/math.py +20 -10
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/indexing.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/type.py +1 -1
- {pytensor-3.1.3 → pytensor-3.2.1/pytensor.egg-info}/PKG-INFO +7 -5
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor.egg-info/SOURCES.txt +4 -2
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor.egg-info/requires.txt +7 -4
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_rop.py +54 -1
- pytensor-3.1.3/pytensor/graph/rewriting/kanren.py +0 -99
- pytensor-3.1.3/pytensor/graph/rewriting/unify.py +0 -497
- pytensor-3.1.3/pytensor/sparse/__init__.py +0 -35
- pytensor-3.1.3/pytensor/tensor/c_code/dimshuffle.c +0 -86
- {pytensor-3.1.3 → pytensor-3.2.1}/LICENSE.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/MANIFEST.in +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/README.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/.templates/PLACEHOLDER +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/.templates/layout.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/.templates/nb-badges.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/.templates/rendered_citation.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/LICENSE.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/README.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/_drafts/benchmark_mlx_v_jax_corrected.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/_thumbnails/autodiff/vector_jacobian_product.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/acknowledgement.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/bcast.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/bcast.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/blog.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/conf.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/core_development_guide.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/css.inc +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/dev_start_guide.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/environment.yml +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/apply.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/apply.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/apply2.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/creating_a_numba_jax_op.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/creating_an_op.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/ctype.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/extending_faq.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/extending_pytensor_solution_1.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/graphstructures.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/inplace.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/op.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/other_ops.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/pics/symbolic_graph_opt.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/pics/symbolic_graph_unopt.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/pipeline.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/scan.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/tips.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/type.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/unittest.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/extending/using_params.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/faq.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/applications/normalizing_flows_in_pytensor.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/applications/tiny_transformer_llm.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/autodiff/vector_jacobian_product.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/introduction/pytensor_intro.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/optimize/root.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/page_footer.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/rewrites/graph_rewrites.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/gallery/scan/scan_tutorial.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/generate_dtype_tensor_table.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/glossary.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/Elman_srnn.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/PyTensor.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/PyTensor_RGB.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/PyTensor_logo.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/binder.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/blocksparse.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/colab.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/github.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/lstm.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/lstm_memorycell.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/talk2010.gif +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/images/talk2010.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/install.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/internal/how_to_release.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/internal/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/internal/metadocumentation.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/introduction.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/debugmode.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/function.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/io.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/mode.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/nanguardmode.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/opfromgraph.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/ops.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/profilemode.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/compile/shared.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/config.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/css/d3viz.css +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/js/d3viz.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/mlp.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/mlp.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/mlp2.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/mlp2.pdf +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/mlp2.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/ofg.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/examples/ofg2.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index.ipynb +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index_files/index_10_0.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index_files/index_11_0.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index_files/index_24_0.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/d3viz/index_files/index_25_0.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/features.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/fgraph.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/graph.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/op.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/replace.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/type.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/graph/utils.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/misc/pkl_utils.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/printing.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/scalar/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/scan.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/sparse/sandbox.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/basic.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/basic_opt.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/bcast.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/bcast.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/elemwise.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/extra_ops.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/fft.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/functional.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/io.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/linalg.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/math_opt.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/nlinalg.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/optimize.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/plot_fft.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/random.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/slinalg.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/tensor/utils.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/typed_list.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/index.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/linalg.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/math.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/module_functions.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/random.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/signal.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/library/xtensor/type.md +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/links.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/optimizations.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/pylintrc +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/robots.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/troubleshooting.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/adding.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/adding_solution_1.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/aliasing.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/apply.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/apply.svg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/bcast.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/broadcasting.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/conditions.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/debug_faq.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/dlogistic.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/examples.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/faq_tutorial.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/gradients.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/index.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/loading_and_saving.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/logistic.gp +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/logistic.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/loop.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/loop_solution_1.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/modes.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/modes_solution_1.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/multi_cores.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/nan_tutorial.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/pics/d3viz.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/pics/logreg_pydotprint_predict.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/pics/logreg_pydotprint_prediction.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/pics/logreg_pydotprint_train.png +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/printing_drawing.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/prng.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/profiling.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/profiling_example.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/profiling_example_out.prof +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/shape_info.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/sparse.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/tutorial/symbolic_graphs.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/doc/user_guide.rst +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/_sparse_lazy.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/alloc.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/core.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/diagonal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/dimshuffle.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/dot.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/elemwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/orthogonal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/permutation.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/positive_definite.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/reshape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/selection.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/specify.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/subtensor.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/symmetric.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/assumptions/triangular.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/bin/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/bin/pytensor_cache.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/breakpoint.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/aliasing.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/compiledir.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/compilelock.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/debugmode.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/dump.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/monitormode.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/nanguardmode.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/debug/profiling.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/executor.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/inner_function.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/io.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/maker.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/rebuild.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/rewriting.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/compile/sharedvalue.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/configparser.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/css/d3viz.css +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/d3viz.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/formatting.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/html/template.html +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/js/d3viz.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/gradient.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/destroyhandler.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/fg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/null_type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/op.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/replace.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/rewriting/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/rewriting/db.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/rewriting/reachability.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/rewriting/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/traversal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/graph/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/ifelse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/ipython.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/c_code/lazylinker_c.c +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/c_code/pytensor_mod_helper.h +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/cutils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/cvm.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/exceptions.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/interface.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/lazylinker_c.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/params_type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/c/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/blas.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/einsum.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/elemwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/extra_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/constructors.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/solvers.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/math.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/pad.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/random.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/scalar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/scan.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/signal/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/signal/conv.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/sort.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/dispatch/sparse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/jax/ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/blas.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/einsum.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/elemwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/extra_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/solvers.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/math.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/pad.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/scalar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/signal/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/signal/conv.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/sort.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/dispatch/tensor_basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/mlx/linker.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/cache.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/compile_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/cython_support.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/extra_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/_LAPACK.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/constructors.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/cholesky.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/dispatch.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/eigen.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/lu.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/lu_factor.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/qr.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/qz.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/schur.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/decomposition/svd.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/cholesky.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/dispatch.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/general.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/hermitian.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/linear_control.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/lu_solve.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/posdef.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/symmetric.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/triangular.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/tridiagonal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/solvers/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/linalg/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/scalar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/scan.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/signal/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/signal/conv.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/sort.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/sparse/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/sparse/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/sparse/math.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/sparse/variable.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/string_codegen.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/tensor_basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/dispatch/typed_list.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/numba/linker.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/blas.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/elemwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/extra_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/linalg/decomposition.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/math.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/scalar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/dispatch/sort.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/pytorch/linker.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/link/vm.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/check_blas.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/check_blas_many.sh +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/check_duplicate_key.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/elemwise_openmp_speedup.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/elemwise_time_test.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/frozendict.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/may_share_memory.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/ordered_set.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/misc/pkl_utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/npy_2_compat.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/printing.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/py.typed +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/raise_op.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/c_code/Faddeeva.cc +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/c_code/Faddeeva.hh +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/c_code/incbet.c +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/loop.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scalar/sharedvar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/checkpoints.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/op.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/db.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/inplace.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/io.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/merge.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/push_out.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/rewriting/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/scan_perform.pyx +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/scan_perform_ext.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/scan/views.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/linalg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/rewriting.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/sharedvar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/sparse/variable.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/_core.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/batched.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/blas_c.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/c_code/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/c_code/alt_blas_common.h +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/c_code/alt_blas_template.c +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/c_code/blas_headers.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/c_code/codegen.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/gemm.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/gemv.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blas/ger.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/einsum.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/elemwise_cgen.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/exceptions.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/fft.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/fourier.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/functional.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/interpolate.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/_lazy.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/constructors.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/cholesky.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/eigen.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/lu.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/qr.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/schur.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/decomposition/svd.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/dtype_utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/core.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/general.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/linear_control.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/lstsq.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/psd.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/triangular.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/solvers/tridiagonal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/nlinalg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/optimize.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/pad.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/op.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/rewriting/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/rewriting/jax.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/rewriting/numba.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/random/variable.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/reshape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/assumptions.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/blas.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/blas_c.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/blockwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/einsum.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/elemwise.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/extra_ops.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/jax.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/decomposition.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/inverse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/products.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/solvers.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/summary.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/linalg/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/ofg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/optimize.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/reshape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/rewriting/uncanonicalize.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/sharedvar.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/signal/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/signal/conv.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/slinalg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/sort.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/special.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/symbolic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/type_other.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/var.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/variable.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/tensor/xlogx.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/typed_list/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/typed_list/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/typed_list/rewriting.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/typed_list/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/indexing.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/linalg.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/random/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/random/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/random/type.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/random/variable.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/reduction.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/__init__.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/math.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/reduction.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/utils.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/rewriting/vectorization.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/shape.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/signal.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor/xtensor/vectorization.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor.egg-info/dependency_links.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor.egg-info/entry_points.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/pytensor.egg-info/top_level.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/scripts/mypy-failing.txt +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/scripts/slowest_tests/update-slowest-times-issue.sh +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/setup.cfg +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/setup.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/link/c/c_code/test_cenum.h +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/link/c/c_code/test_quadratic_function.c +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_basic.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_breakpoint.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_config.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_gradient.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_ifelse.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_printing.py +0 -0
- {pytensor-3.1.3 → pytensor-3.2.1}/tests/test_raise_op.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytensor
|
|
3
|
-
Version: 3.1
|
|
3
|
+
Version: 3.2.1
|
|
4
4
|
Summary: Optimizing compiler for evaluating mathematical expressions on CPUs and GPUs.
|
|
5
5
|
Author-email: pymc-devs <pymc.devs@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -32,10 +32,6 @@ Requires-Dist: scipy<2,>=1
|
|
|
32
32
|
Requires-Dist: numpy>=2.0
|
|
33
33
|
Requires-Dist: numba<=0.65.1,>=0.58
|
|
34
34
|
Requires-Dist: filelock>=3.15
|
|
35
|
-
Requires-Dist: etuples
|
|
36
|
-
Requires-Dist: logical-unification
|
|
37
|
-
Requires-Dist: miniKanren
|
|
38
|
-
Requires-Dist: cons
|
|
39
35
|
Provides-Extra: complete
|
|
40
36
|
Requires-Dist: pytensor[jax]; extra == "complete"
|
|
41
37
|
Requires-Dist: pytensor[numba]; extra == "complete"
|
|
@@ -51,6 +47,7 @@ Requires-Dist: coverage>=5.1; extra == "tests"
|
|
|
51
47
|
Requires-Dist: pytest-benchmark; extra == "tests"
|
|
52
48
|
Requires-Dist: pytest-mock; extra == "tests"
|
|
53
49
|
Requires-Dist: pytest-sphinx; extra == "tests"
|
|
50
|
+
Requires-Dist: pytensor[kanren]; extra == "tests"
|
|
54
51
|
Provides-Extra: rtd
|
|
55
52
|
Requires-Dist: sphinx<6,>=5.1.0; extra == "rtd"
|
|
56
53
|
Requires-Dist: pygments; extra == "rtd"
|
|
@@ -61,6 +58,11 @@ Requires-Dist: jaxlib; extra == "jax"
|
|
|
61
58
|
Provides-Extra: numba
|
|
62
59
|
Requires-Dist: numba<=0.65.1,>=0.58; extra == "numba"
|
|
63
60
|
Requires-Dist: llvmlite; extra == "numba"
|
|
61
|
+
Provides-Extra: kanren
|
|
62
|
+
Requires-Dist: etuples; extra == "kanren"
|
|
63
|
+
Requires-Dist: logical-unification; extra == "kanren"
|
|
64
|
+
Requires-Dist: miniKanren; extra == "kanren"
|
|
65
|
+
Requires-Dist: cons; extra == "kanren"
|
|
64
66
|
Dynamic: license-file
|
|
65
67
|
|
|
66
68
|
.. image:: https://cdn.rawgit.com/pymc-devs/pytensor/main/doc/images/PyTensor_RGB.svg
|
|
@@ -713,322 +713,6 @@ C code.
|
|
|
713
713
|
return c_code % locals()
|
|
714
714
|
|
|
715
715
|
|
|
716
|
-
Alternate way of defining C :class:`Op`\s
|
|
717
|
-
=========================================
|
|
718
|
-
|
|
719
|
-
The two previous examples have covered the standard way of implementing C :class:`Op`\s
|
|
720
|
-
in PyTensor by inheriting from the class :class:`Op`. This process is mostly
|
|
721
|
-
simple but it still involves defining many methods as well as mixing, in the
|
|
722
|
-
same file, both Python and C code which tends to make the result less
|
|
723
|
-
readable.
|
|
724
|
-
|
|
725
|
-
To help with this, PyTensor defines a class, `ExternalCOp`, from which new C :class:`Op`\s
|
|
726
|
-
can inherit. The class `ExternalCOp` aims to simplify the process of implementing
|
|
727
|
-
C :class:`Op`\s by doing the following :
|
|
728
|
-
|
|
729
|
-
* It allows you to define the C implementation of your :class:`Op` in a distinct
|
|
730
|
-
C code file. This makes it easier to keep your Python and C code
|
|
731
|
-
readable and well indented.
|
|
732
|
-
|
|
733
|
-
* It can automatically handle all the methods that return C code,
|
|
734
|
-
in addition to :meth:`Op.c_code_cache_version` based on the
|
|
735
|
-
provided external C implementation.
|
|
736
|
-
|
|
737
|
-
To illustrate how much simpler the class `ExternalCOp` makes the process of defining
|
|
738
|
-
a new :class:`Op` with a C implementation, let's revisit the second example of this
|
|
739
|
-
tutorial, the `VectorTimesVector`\ :class:`Op`. In that example, we implemented an :class:`Op`
|
|
740
|
-
to perform the task of element-wise vector-vector multiplication. The two
|
|
741
|
-
following blocks of code illustrate what the :class:`Op` would look like if it was
|
|
742
|
-
implemented using the `ExternalCOp` class.
|
|
743
|
-
|
|
744
|
-
The new :class:`Op` is defined inside a Python file with the following code :
|
|
745
|
-
|
|
746
|
-
.. testcode::
|
|
747
|
-
|
|
748
|
-
import pytensor
|
|
749
|
-
from pytensor.link.c.op import ExternalCOp
|
|
750
|
-
|
|
751
|
-
class VectorTimesVector(ExternalCOp):
|
|
752
|
-
__props__ = ()
|
|
753
|
-
|
|
754
|
-
func_file = "./vectorTimesVector.c"
|
|
755
|
-
func_name = "APPLY_SPECIFIC(vector_times_vector)"
|
|
756
|
-
|
|
757
|
-
def __init__(self):
|
|
758
|
-
super().__init__(self.func_file, self.func_name)
|
|
759
|
-
|
|
760
|
-
def make_node(self, x, y):
|
|
761
|
-
# Validate the inputs' type
|
|
762
|
-
if x.type.ndim != 1:
|
|
763
|
-
raise TypeError('x must be a 1-d vector')
|
|
764
|
-
if y.type.ndim != 1:
|
|
765
|
-
raise TypeError('y must be a 1-d vector')
|
|
766
|
-
|
|
767
|
-
# Create an output variable of the same type as x
|
|
768
|
-
output_var = pytensor.tensor.type.TensorType(
|
|
769
|
-
dtype=pytensor.scalar.upcast(x.dtype, y.dtype),
|
|
770
|
-
shape=(None,))()
|
|
771
|
-
|
|
772
|
-
return Apply(self, [x, y], [output_var])
|
|
773
|
-
|
|
774
|
-
And the following is the C implementation of the :class:`Op`, defined in an external
|
|
775
|
-
C file named ``vectorTimesVector.c``:
|
|
776
|
-
|
|
777
|
-
.. code-block:: c
|
|
778
|
-
|
|
779
|
-
#section support_code
|
|
780
|
-
|
|
781
|
-
// Support code function
|
|
782
|
-
bool vector_same_shape(PyArrayObject* arr1, PyArrayObject* arr2)
|
|
783
|
-
{
|
|
784
|
-
return (PyArray_DIMS(arr1)[0] == PyArray_DIMS(arr2)[0]);
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
#section support_code_apply
|
|
789
|
-
|
|
790
|
-
// Apply-specific support function
|
|
791
|
-
void APPLY_SPECIFIC(vector_elemwise_mult)(
|
|
792
|
-
DTYPE_INPUT_0* x_ptr, int x_str,
|
|
793
|
-
DTYPE_INPUT_1* y_ptr, int y_str,
|
|
794
|
-
DTYPE_OUTPUT_0* z_ptr, int z_str, int nbElements)
|
|
795
|
-
{
|
|
796
|
-
for (int i=0; i < nbElements; i++){
|
|
797
|
-
z_ptr[i * z_str] = x_ptr[i * x_str] * y_ptr[i * y_str];
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
// Apply-specific main function
|
|
802
|
-
int APPLY_SPECIFIC(vector_times_vector)(PyArrayObject* input0,
|
|
803
|
-
PyArrayObject* input1,
|
|
804
|
-
PyArrayObject** output0)
|
|
805
|
-
{
|
|
806
|
-
// Validate that the inputs have the same shape
|
|
807
|
-
if ( !vector_same_shape(input0, input1))
|
|
808
|
-
{
|
|
809
|
-
PyErr_Format(PyExc_ValueError, "Shape mismatch : "
|
|
810
|
-
"input0.shape[0] and input1.shape[0] should "
|
|
811
|
-
"match but x.shape[0] == %i and "
|
|
812
|
-
"y.shape[0] == %i",
|
|
813
|
-
PyArray_DIMS(input0)[0], PyArray_DIMS(input1)[0]);
|
|
814
|
-
return 1;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
// Validate that the output storage exists and has the same
|
|
818
|
-
// dimension as x.
|
|
819
|
-
if (NULL == *output0 || !(vector_same_shape(input0, *output0)))
|
|
820
|
-
{
|
|
821
|
-
/* Reference received to invalid output variable.
|
|
822
|
-
Decrease received reference's ref count and allocate new
|
|
823
|
-
output variable */
|
|
824
|
-
Py_XDECREF(*output0);
|
|
825
|
-
*output0 = (PyArrayObject*)PyArray_EMPTY(1,
|
|
826
|
-
PyArray_DIMS(input0),
|
|
827
|
-
TYPENUM_OUTPUT_0,
|
|
828
|
-
0);
|
|
829
|
-
|
|
830
|
-
if (!*output0) {
|
|
831
|
-
PyErr_Format(PyExc_ValueError,
|
|
832
|
-
"Could not allocate output storage");
|
|
833
|
-
return 1;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// Perform the actual vector-vector multiplication
|
|
838
|
-
APPLY_SPECIFIC(vector_elemwise_mult)(
|
|
839
|
-
(DTYPE_INPUT_0*)PyArray_DATA(input0),
|
|
840
|
-
PyArray_STRIDES(input0)[0] / ITEMSIZE_INPUT_0,
|
|
841
|
-
(DTYPE_INPUT_1*)PyArray_DATA(input1),
|
|
842
|
-
PyArray_STRIDES(input1)[0] / ITEMSIZE_INPUT_1,
|
|
843
|
-
(DTYPE_OUTPUT_0*)PyArray_DATA(*output0),
|
|
844
|
-
PyArray_STRIDES(*output0)[0] / ITEMSIZE_OUTPUT_0,
|
|
845
|
-
PyArray_DIMS(input0)[0]);
|
|
846
|
-
|
|
847
|
-
return 0;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
As you can see from this example, the Python and C implementations are nicely
|
|
851
|
-
decoupled which makes them much more readable than when they were intertwined
|
|
852
|
-
in the same file and the C code contained string formatting markers.
|
|
853
|
-
|
|
854
|
-
Now that we have motivated the `ExternalCOp` class, we can have a more precise look at
|
|
855
|
-
what it does for us. For this, we go through the various elements that make up
|
|
856
|
-
this new version of the `VectorTimesVector`\ `Op` :
|
|
857
|
-
|
|
858
|
-
* Parent class : instead of inheriting from the class :class:`Op`,
|
|
859
|
-
VectorTimesVector inherits from the class `ExternalCOp`.
|
|
860
|
-
|
|
861
|
-
* Constructor : in our new `COp`, the :meth:`COp.__init__` method has an
|
|
862
|
-
important use; to inform the constructor of the `ExternalCOp` class
|
|
863
|
-
of the location, on the filesystem of the C implementation of
|
|
864
|
-
this `COp`. To do this, it gives a list of file paths containing
|
|
865
|
-
the C code for this `COp`. To auto-generate the c_code method
|
|
866
|
-
with a function call you can specify the function name as the
|
|
867
|
-
second parameter. The paths should be given as a relative
|
|
868
|
-
path from the folder where the descendant of the `ExternalCOp` class
|
|
869
|
-
is defined.
|
|
870
|
-
|
|
871
|
-
* :meth:`ExternalCOp.make_node` : this method is absolutely
|
|
872
|
-
identical to the one in our old example. Using the `ExternalCOp`
|
|
873
|
-
class doesn't change anything here.
|
|
874
|
-
|
|
875
|
-
* External C code : the external C code implements the various
|
|
876
|
-
functions associated with the `COp`. Writing this C code
|
|
877
|
-
involves a few subtleties which deserve their own respective
|
|
878
|
-
sections.
|
|
879
|
-
|
|
880
|
-
Main function
|
|
881
|
-
-------------
|
|
882
|
-
|
|
883
|
-
If you pass a function name to :meth:`ExternalCOp.__init___`, it must respect
|
|
884
|
-
the following constraints:
|
|
885
|
-
|
|
886
|
-
* It must return an int. The value of that int indicates whether
|
|
887
|
-
the `Op` could perform its task or not. A value of 0 indicates
|
|
888
|
-
success while any non-zero value will interrupt the execution
|
|
889
|
-
of the PyTensor function. When returning non-zero the function
|
|
890
|
-
must set a python exception indicating the details of the
|
|
891
|
-
problem.
|
|
892
|
-
|
|
893
|
-
* It must receive one argument for each input to the `Op` followed
|
|
894
|
-
by one pointer to an argument for each output of the `Op`. The
|
|
895
|
-
types for the argument is dependent on the Types (that is
|
|
896
|
-
pytensor Types) of your inputs and outputs.
|
|
897
|
-
|
|
898
|
-
* You can specify the number of inputs and outputs for your `Op`
|
|
899
|
-
by setting the ``_cop_num_inputs`` and ``_cop_num_outputs``
|
|
900
|
-
attributes on your `COp`. The main function will always be
|
|
901
|
-
called with that number of arguments, using NULL to fill in
|
|
902
|
-
for missing values at the end. This can be used if your `COp`
|
|
903
|
-
has a variable number of inputs or outputs, but with a fixed
|
|
904
|
-
maximum.
|
|
905
|
-
|
|
906
|
-
For example, the main C function of an `COp` that takes two TensorTypes
|
|
907
|
-
(which has ``PyArrayObject *`` as its C type) as inputs and returns
|
|
908
|
-
both their sum and the difference between them would have four
|
|
909
|
-
parameters (two for the `COp`'s inputs and two for its outputs) and it's
|
|
910
|
-
signature would look something like this :
|
|
911
|
-
|
|
912
|
-
.. code-block:: c
|
|
913
|
-
|
|
914
|
-
int sumAndDiffOfScalars(PyArrayObject* in0, PyArrayObject* in1,
|
|
915
|
-
PyArrayObject** out0, PyArrayObject** out1)
|
|
916
|
-
|
|
917
|
-
Macros
|
|
918
|
-
------
|
|
919
|
-
|
|
920
|
-
For certain section tags, your C code can benefit from a number of
|
|
921
|
-
pre-defined macros. These section tags have no macros: ``init_code``,
|
|
922
|
-
``support_code``. All other tags will have the support macros
|
|
923
|
-
discussed below.
|
|
924
|
-
|
|
925
|
-
* ``APPLY_SPECIFIC(str)`` which will automatically append a name
|
|
926
|
-
unique to the :ref:`apply` node that applies the `Op` at the end
|
|
927
|
-
of the provided ``str``. The use of this macro is discussed
|
|
928
|
-
further below.
|
|
929
|
-
|
|
930
|
-
For every input which has a :attr:`dtype` attribute (this means
|
|
931
|
-
Tensors), the following macros will be
|
|
932
|
-
defined unless your `Op` class has an :attr:`Op.check_input` attribute
|
|
933
|
-
defined to False. In these descriptions 'i' refers to the position
|
|
934
|
-
(indexed from 0) in the input array.
|
|
935
|
-
|
|
936
|
-
* ``DTYPE_INPUT_{i}`` : NumPy dtype of the data in the array.
|
|
937
|
-
This is the variable type corresponding to the NumPy dtype, not the
|
|
938
|
-
string representation of the NumPy dtype. For instance, if the `Op`'s
|
|
939
|
-
first input is a float32 :class:`ndarray`, then the macro ``DTYPE_INPUT_0``
|
|
940
|
-
corresponds to ``npy_float32`` and can directly be used to declare a
|
|
941
|
-
new variable of the same dtype as the data in the array :
|
|
942
|
-
|
|
943
|
-
.. code-block:: c
|
|
944
|
-
|
|
945
|
-
DTYPE_INPUT_0 myVar = someValue;
|
|
946
|
-
|
|
947
|
-
* ``TYPENUM_INPUT_{i}`` : Typenum of the data in the array
|
|
948
|
-
|
|
949
|
-
* ``ITEMSIZE_INPUT_{i}`` : Size, in bytes, of the elements in
|
|
950
|
-
the array.
|
|
951
|
-
|
|
952
|
-
In the same way, the macros ``DTYPE_OUTPUT_{i}``,
|
|
953
|
-
``ITEMSIZE_OUTPUT_{i}`` and ``TYPENUM_OUTPUT_{i}`` are defined for
|
|
954
|
-
every output 'i' of the `Op`.
|
|
955
|
-
|
|
956
|
-
In addition to these macros, the ``init_code_struct``, ``code``, and
|
|
957
|
-
``code_cleanup`` section tags also have the following macros:
|
|
958
|
-
|
|
959
|
-
* ``FAIL`` : Code to insert at error points. A python exception
|
|
960
|
-
should be set prior to this code. An invocation look like this:
|
|
961
|
-
|
|
962
|
-
.. code-block:: c
|
|
963
|
-
|
|
964
|
-
if (error) {
|
|
965
|
-
// Set python exception
|
|
966
|
-
FAIL
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
You can add a semicolon after the macro if it makes your editor
|
|
970
|
-
happy.
|
|
971
|
-
|
|
972
|
-
* ``PARAMS`` : Name of the params variable for this node. (only
|
|
973
|
-
for `Op`\s which have params, which is discussed elsewhere)
|
|
974
|
-
|
|
975
|
-
Finally the tag ``code`` and ``code_cleanup`` have macros to
|
|
976
|
-
pass the inputs and output names. These are name ``INPUT_{i}`` and
|
|
977
|
-
``OUTPUT_{i}`` where `i` is the 0-based index position in the input
|
|
978
|
-
and output arrays respectively.
|
|
979
|
-
|
|
980
|
-
Support code
|
|
981
|
-
------------
|
|
982
|
-
|
|
983
|
-
Certain section are limited in what you can place in them due to
|
|
984
|
-
semantic and syntactic restrictions of the C++ language. Most of
|
|
985
|
-
these restrictions apply to the tags that end in ``_struct``.
|
|
986
|
-
|
|
987
|
-
When we defined the ``VectorTimesVector`` `Op` without using the ``ExternalCOp``
|
|
988
|
-
class, we had to make a distinction between two types of support_code
|
|
989
|
-
: the support code that was apply-specific and the support code that
|
|
990
|
-
wasn't. The apply-specific code was defined in the
|
|
991
|
-
``c_support_code_apply`` method and the elements defined in that
|
|
992
|
-
code (global variables and functions) had to include the name of the
|
|
993
|
-
Apply node in their own names to avoid conflicts between the different
|
|
994
|
-
versions of the apply-specific code. The code that wasn't
|
|
995
|
-
apply-specific was simply defined in the ``c_support_code`` method.
|
|
996
|
-
|
|
997
|
-
To make indentifiers that include the :ref:`apply` node name use the
|
|
998
|
-
``APPLY_SPECIFIC(str)`` macro. In the above example, this macro is
|
|
999
|
-
used when defining the functions ``vector_elemwise_mult`` and
|
|
1000
|
-
``vector_times_vector`` as well as when calling function
|
|
1001
|
-
``vector_elemwise_mult`` from inside ``vector_times_vector``.
|
|
1002
|
-
|
|
1003
|
-
When using the ``ExternalCOp`` class, we still have to make the distinction
|
|
1004
|
-
between C code for each of the methods of a C class. These sections of
|
|
1005
|
-
code are separated by ``#section <tag>`` markers. The tag determines
|
|
1006
|
-
the name of the method this C code applies to with the rule that
|
|
1007
|
-
``<tag>`` applies to `c_<tag>`. Unknown tags are an error and will be
|
|
1008
|
-
reported. Duplicate tags will be merged together in the order the
|
|
1009
|
-
appear in the C files.
|
|
1010
|
-
|
|
1011
|
-
The rules for knowing if where a piece of code should be put can be
|
|
1012
|
-
sometimes tricky. The key thing to remember is that things that can
|
|
1013
|
-
be shared between instances of the `Op` should be apply-agnostic and go
|
|
1014
|
-
into a section which does not end in ``_apply`` or ``_struct``. The
|
|
1015
|
-
distinction of ``_apply`` and ``_struct`` mostly hinghes on how you
|
|
1016
|
-
want to manage the lifetime of the object. Note that to use an
|
|
1017
|
-
apply-specific object, you have to be in a apply-specific section, so
|
|
1018
|
-
some portions of the code that might seem apply-agnostic may still be
|
|
1019
|
-
apply-specific because of the data they use (this does not include
|
|
1020
|
-
arguments).
|
|
1021
|
-
|
|
1022
|
-
In the above example, the ``function vector_same_shape`` is
|
|
1023
|
-
apply-agnostic because it uses none of the macros defined by the class
|
|
1024
|
-
``ExternalCOp`` and it doesn't rely on any apply-specific code. The function
|
|
1025
|
-
``vector_elemwise_mult`` is apply-specific because it uses the
|
|
1026
|
-
macros defined by ``ExternalCOp``. Finally, the function
|
|
1027
|
-
``vector_times_vector`` is apply-specific because it uses those same
|
|
1028
|
-
macros and also because it calls ``vector_elemwise_mult`` which is
|
|
1029
|
-
an apply-specific function.
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
716
|
Using GDB to debug :class:`COp`'s C code
|
|
1033
717
|
========================================
|
|
1034
718
|
|
|
@@ -324,229 +324,14 @@ or :class:`PatternNodeRewriter`, it is highly recommended to use them.
|
|
|
324
324
|
|
|
325
325
|
.. _unification:
|
|
326
326
|
|
|
327
|
-
Unification and
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
The :class:`PatternNodeRewriter` class uses `unification and reification
|
|
331
|
-
<https://en.wikipedia.org/wiki/Unification_(computer_science)>`_ to implement a
|
|
332
|
-
more succinct and reusable form of "pattern matching and replacement".
|
|
333
|
-
In general, *use of the unification and reification tools is preferable when
|
|
334
|
-
a rewrite's matching and replacement are non-trivial*, so we will briefly explain
|
|
335
|
-
them in the following.
|
|
336
|
-
|
|
337
|
-
PyTensor's unification and reification tools are provided by the
|
|
338
|
-
`logical-unification <https://github.com/pythological/unification>`_ package.
|
|
339
|
-
The basic tools are :func:`unify`, :func:`reify`, and :class:`var`. The class :class:`var`
|
|
340
|
-
construct *logic variables*, which represent the elements to be unified/matched, :func:`unify`
|
|
341
|
-
performs the "matching", and :func:`reify` performs the "replacements".
|
|
342
|
-
|
|
343
|
-
See :mod:`unification`'s documentation for an introduction to unification and reification.
|
|
344
|
-
|
|
345
|
-
In order to use :func:`unify` and :func:`reify` with PyTensor graphs, we need an intermediate
|
|
346
|
-
structure that will allow us to represent PyTensor graphs that contain :class:`var`\s, because
|
|
347
|
-
PyTensor :class:`Op`\s and :class:`Apply` nodes will not accept these foreign objects as inputs.
|
|
348
|
-
|
|
349
|
-
:class:`PatternNodeRewriter` uses Python ``tuple``\s to effectively represent :class:`Apply` nodes and
|
|
350
|
-
``str``\s to represent logic variables (i.e. :class:`var`\s in the :mod:`unification` library).
|
|
351
|
-
Behind the scenes, these ``tuple``\s are converted to a ``tuple`` subclass called :class:`ExpressionTuple`\s,
|
|
352
|
-
which behave just like normal ``tuple``\s except for some special caching features that allow for easy
|
|
353
|
-
evaluation and caching. These :class:`ExpressionTuple`\s are provided by the
|
|
354
|
-
`etuples <https://github.com/pythological/etuples>`_ library.
|
|
355
|
-
|
|
356
|
-
Here is an illustration of all the above components used together:
|
|
357
|
-
|
|
358
|
-
>>> from unification import unify, reify, var
|
|
359
|
-
>>> from etuples import etuple
|
|
360
|
-
>>> y_lv = var() # Create a logic variable
|
|
361
|
-
>>> y_lv
|
|
362
|
-
~_1
|
|
363
|
-
>>> s = unify(add(x, y), etuple(add, x, y_lv))
|
|
364
|
-
>>> s
|
|
365
|
-
{~_1: y}
|
|
366
|
-
|
|
367
|
-
In this example, :func:`unify` matched the PyTensor graph in the first argument with the "pattern"
|
|
368
|
-
given by the :func:`etuple` in the second. The result is a ``dict`` mapping logic variables to
|
|
369
|
-
the objects to which they were successfully unified. When a :func:`unify` doesn't succeed, it will
|
|
370
|
-
return ``False``.
|
|
371
|
-
|
|
372
|
-
:func:`reify` uses ``dict``\s like the kind produced by :func:`unify` to replace
|
|
373
|
-
logic variables within structures:
|
|
374
|
-
|
|
375
|
-
>>> res = reify(etuple(add, y_lv, y_lv), s)
|
|
376
|
-
>>> res
|
|
377
|
-
e(<pytensor.scalar.basic.Add at 0x7f54dfa5a350>, y, y)
|
|
378
|
-
|
|
379
|
-
Since :class:`ExpressionTuple`\s can be evaluated, we can produce a complete PyTensor graph from these
|
|
380
|
-
results as follows:
|
|
381
|
-
|
|
382
|
-
>>> res.evaled_obj
|
|
383
|
-
add.0
|
|
384
|
-
>>> pytensor.dprint(res.evaled_obj)
|
|
385
|
-
add [id A] ''
|
|
386
|
-
|y [id B]
|
|
387
|
-
|y [id B]
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
Because :class:`ExpressionTuple`\s effectively model `S-expressions
|
|
391
|
-
<https://en.wikipedia.org/wiki/S-expression>`_, they can be used with the `cons
|
|
392
|
-
<https://github.com/pythological/python-cons>`_ package to unify and reify
|
|
393
|
-
graphs structurally.
|
|
394
|
-
|
|
395
|
-
Let's say we want to match graphs that use the :class:`add`\ :class:`Op` but could have a
|
|
396
|
-
varying number of arguments:
|
|
397
|
-
|
|
398
|
-
>>> from cons import cons
|
|
399
|
-
>>> op_lv = var()
|
|
400
|
-
>>> args_lv = var()
|
|
401
|
-
>>> s = unify(cons(op_lv, args_lv), add(x, y))
|
|
402
|
-
>>> s
|
|
403
|
-
{~_2: <pytensor.scalar.basic.Add at 0x7f54dfa5a350>, ~_3: e(x, y)}
|
|
404
|
-
>>> s = unify(cons(op_lv, args_lv), add(x, y, z))
|
|
405
|
-
>>> s
|
|
406
|
-
{~_2: <pytensor.scalar.basic.Add at 0x7f54dfa5a350>, ~_3: e(x, y, z)}
|
|
407
|
-
|
|
408
|
-
From here, we can check ``s[op_lv] == add`` to confirm that we have the correct :class:`Op` and
|
|
409
|
-
proceed with our rewrite.
|
|
410
|
-
|
|
411
|
-
>>> res = reify(cons(mul, args_lv), s)
|
|
412
|
-
>>> res
|
|
413
|
-
e(<pytensor.scalar.basic.Mul at 0x7f54dfa5ae10>, x, y, z)
|
|
414
|
-
>>> pytensor.dprint(res.evaled_obj)
|
|
415
|
-
mul [id A] ''
|
|
416
|
-
|x [id B]
|
|
417
|
-
|y [id C]
|
|
418
|
-
|z [id D]
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
.. _miniKanren_rewrites:
|
|
422
|
-
|
|
423
|
-
miniKanren
|
|
424
|
-
==========
|
|
425
|
-
|
|
426
|
-
Given that unification and reification are fully implemented for PyTensor objects via the :mod:`unificiation` package,
|
|
427
|
-
the `kanren <https://github.com/pythological/kanren>`_ package can be used with PyTensor graphs, as well.
|
|
428
|
-
:mod:`kanren` implements the `miniKanren <http://minikanren.org/>`_ domain-specific language for relational programming.
|
|
429
|
-
|
|
430
|
-
Refer to the links above for a proper introduction to miniKanren, but suffice it to say that
|
|
431
|
-
miniKanren orchestrates the unification and reification operations described in :ref:`unification`, and
|
|
432
|
-
it does so in the context of relational operators (e.g. equations like :math:`x + x = 2 x`).
|
|
433
|
-
This means that a relation that--say--represents :math:`x + x = 2 x` can be
|
|
434
|
-
utilized in both directions.
|
|
435
|
-
|
|
436
|
-
Currently, the node rewriter :class:`KanrenRelationSub` provides a means of
|
|
437
|
-
turning :mod:`kanren` relations into :class:`NodeRewriter`\s; however,
|
|
438
|
-
:mod:`kanren` can always be used directly from within a custom :class:`Rewriter`, so
|
|
439
|
-
:class:`KanrenRelationSub` is not necessary.
|
|
440
|
-
|
|
441
|
-
The following is an example that distributes dot products across additions.
|
|
442
|
-
|
|
443
|
-
.. code::
|
|
444
|
-
|
|
445
|
-
import pytensor
|
|
446
|
-
import pytensor.tensor as pt
|
|
447
|
-
from pytensor.graph.rewriting.kanren import KanrenRelationSub
|
|
448
|
-
from pytensor.graph.rewriting.basic import EquilibriumGraphRewriter
|
|
449
|
-
from pytensor.graph.rewriting.utils import rewrite_graph
|
|
450
|
-
from pytensor.tensor.math import _dot
|
|
451
|
-
from etuples import etuple
|
|
452
|
-
from kanren import conso, eq, fact, heado, tailo
|
|
453
|
-
from kanren.assoccomm import assoc_flatten, associative
|
|
454
|
-
from kanren.core import lall
|
|
455
|
-
from kanren.graph import mapo
|
|
456
|
-
from unification import vars as lvars
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
# Make the graph pretty printing results a little more readable
|
|
460
|
-
pytensor.pprint.assign(
|
|
461
|
-
_dot, pytensor.printing.OperatorPrinter("@", -1, "left")
|
|
462
|
-
)
|
|
463
|
-
|
|
464
|
-
# Tell `kanren` that `add` is associative
|
|
465
|
-
fact(associative, pt.add)
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
def dot_distributeo(in_lv, out_lv):
|
|
469
|
-
"""A `kanren` goal constructor relation for the relation ``A.dot(a + b ...) == A.dot(a) + A.dot(b) ...``."""
|
|
470
|
-
A_lv, add_term_lv, add_cdr_lv, dot_cdr_lv, add_flat_lv = lvars(5)
|
|
471
|
-
|
|
472
|
-
return lall(
|
|
473
|
-
# Make sure the input is a `_dot`
|
|
474
|
-
eq(in_lv, etuple(_dot, A_lv, add_term_lv)),
|
|
475
|
-
# Make sure the term being `_dot`ed is an `add`
|
|
476
|
-
heado(pt.add, add_term_lv),
|
|
477
|
-
# Flatten the associative pairings of `add` operations
|
|
478
|
-
assoc_flatten(add_term_lv, add_flat_lv),
|
|
479
|
-
# Get the flattened `add` arguments
|
|
480
|
-
tailo(add_cdr_lv, add_flat_lv),
|
|
481
|
-
# Add all the `_dot`ed arguments and set the output
|
|
482
|
-
conso(pt.add, dot_cdr_lv, out_lv),
|
|
483
|
-
# Apply the `_dot` to all the flattened `add` arguments
|
|
484
|
-
mapo(lambda x, y: conso(_dot, etuple(A_lv, x), y), add_cdr_lv, dot_cdr_lv),
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
dot_distribute_rewrite = EquilibriumGraphRewriter([KanrenRelationSub(dot_distributeo)], max_use_ratio=10)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
Below, we apply `dot_distribute_rewrite` to a few example graphs. First we create simple test graph:
|
|
492
|
-
|
|
493
|
-
>>> x_at = pt.vector("x")
|
|
494
|
-
>>> y_at = pt.vector("y")
|
|
495
|
-
>>> A_at = pt.matrix("A")
|
|
496
|
-
>>> test_at = A_pt.dot(x_at + y_at)
|
|
497
|
-
>>> print(pytensor.pprint(test_at))
|
|
498
|
-
(A @ (x + y))
|
|
499
|
-
|
|
500
|
-
Next we apply the rewrite to the graph:
|
|
501
|
-
|
|
502
|
-
>>> res = rewrite_graph(test_at, include=[], custom_rewrite=dot_distribute_rewrite, clone=False)
|
|
503
|
-
>>> print(pytensor.pprint(res))
|
|
504
|
-
((A @ x) + (A @ y))
|
|
505
|
-
|
|
506
|
-
We see that the dot product has been distributed, as desired. Now, let's try a
|
|
507
|
-
few more test cases:
|
|
508
|
-
|
|
509
|
-
>>> z_at = pt.vector("z")
|
|
510
|
-
>>> w_at = pt.vector("w")
|
|
511
|
-
>>> test_at = A_pt.dot((x_at + y_at) + (z_at + w_at))
|
|
512
|
-
>>> print(pytensor.pprint(test_at))
|
|
513
|
-
(A @ ((x + y) + (z + w)))
|
|
514
|
-
>>> res = rewrite_graph(test_at, include=[], custom_rewrite=dot_distribute_rewrite, clone=False)
|
|
515
|
-
>>> print(pytensor.pprint(res))
|
|
516
|
-
(((A @ x) + (A @ y)) + ((A @ z) + (A @ w)))
|
|
517
|
-
|
|
518
|
-
>>> B_at = pt.matrix("B")
|
|
519
|
-
>>> w_at = pt.vector("w")
|
|
520
|
-
>>> test_at = A_pt.dot(x_at + (y_at + B_pt.dot(z_at + w_at)))
|
|
521
|
-
>>> print(pytensor.pprint(test_at))
|
|
522
|
-
(A @ (x + (y + ((B @ z) + (B @ w)))))
|
|
523
|
-
>>> res = rewrite_graph(test_at, include=[], custom_rewrite=dot_distribute_rewrite, clone=False)
|
|
524
|
-
>>> print(pytensor.pprint(res))
|
|
525
|
-
((A @ x) + ((A @ y) + ((A @ (B @ z)) + (A @ (B @ w)))))
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
This example demonstrates how non-trivial matching and replacement logic can
|
|
529
|
-
be neatly expressed in miniKanren's DSL, but it doesn't quite demonstrate miniKanren's
|
|
530
|
-
relational properties.
|
|
531
|
-
|
|
532
|
-
To do that, we will create another :class:`Rewriter` that simply reverses the arguments
|
|
533
|
-
to the relation :func:`dot_distributeo` and apply it to the distributed result in ``res``:
|
|
534
|
-
|
|
535
|
-
>>> dot_gather_rewrite = EquilibriumGraphRewriter([KanrenRelationSub(lambda x, y: dot_distributeo(y, x))], max_use_ratio=10)
|
|
536
|
-
>>> rev_res = rewrite_graph(res, include=[], custom_rewrite=dot_gather_rewrite, clone=False)
|
|
537
|
-
>>> print(pytensor.pprint(rev_res))
|
|
538
|
-
(A @ (x + (y + (B @ (z + w)))))
|
|
539
|
-
|
|
540
|
-
As we can see, the :mod:`kanren` relation works both ways, just like the underlying
|
|
541
|
-
mathematical relation does.
|
|
542
|
-
|
|
543
|
-
miniKanren relations can be used to explore rewrites of graphs in sophisticated
|
|
544
|
-
ways. It also provides a framework that more directly maps to the mathematical
|
|
545
|
-
identities that drive graph rewrites. For some simple examples of relational graph rewriting
|
|
546
|
-
in :mod:`kanren` see `here <https://github.com/pythological/kanren/blob/master/doc/graphs.md>`_. For a
|
|
547
|
-
high-level overview of miniKanren's use as a tool for symbolic computation see
|
|
548
|
-
`"miniKanren as a Tool for Symbolic Computation in Python" <https://arxiv.org/abs/2005.11644>`_.
|
|
327
|
+
Unification, reification and miniKanren
|
|
328
|
+
=======================================
|
|
549
329
|
|
|
330
|
+
For non-trivial pattern matching and replacement, PyTensor optionally exposes
|
|
331
|
+
:func:`unify` / :func:`reify` over :mod:`logical-unification` and miniKanren
|
|
332
|
+
relations via :class:`KanrenRelationSub`. These rely on a set of optional
|
|
333
|
+
packages (:mod:`logical-unification`, :mod:`kanren`, :mod:`etuples`,
|
|
334
|
+
:mod:`cons`) and are documented separately in :ref:`unification_kanren`.
|
|
550
335
|
|
|
551
336
|
.. _testing_rewrites:
|
|
552
337
|
|