pytensor 2.27.0__tar.gz → 2.27.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-2.27.0/pytensor.egg-info → pytensor-2.27.1}/PKG-INFO +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/core_development_guide.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/creating_a_c_op.rst +2 -2
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/creating_an_op.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/inplace.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/other_ops.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/install.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/mode.rst +9 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/random/index.rst +1 -1
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/troubleshooting.rst +65 -26
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/examples.rst +1 -9
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/prng.rst +44 -62
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/_version.py +3 -3
- pytensor-2.27.1/pytensor/graph/rewriting/__init__.py +4 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/rewriting/db.py +19 -12
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/cmodule.py +31 -5
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/basic.py +0 -18
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/elemwise.py +4 -48
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/blas_headers.py +5 -4
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/einsum.py +20 -5
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/math.py +34 -8
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/math.py +92 -5
- {pytensor-2.27.0 → pytensor-2.27.1/pytensor.egg-info}/PKG-INFO +1 -1
- pytensor-2.27.0/pytensor/sparse/sandbox/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/LICENSE.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/MANIFEST.in +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/README.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/.templates/PLACEHOLDER +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/.templates/layout.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/.templates/nb-badges.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/.templates/rendered_citation.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/LICENSE.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/README.md +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/acknowledgement.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/bcast.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/bcast.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/blog.md +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/conf.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/css.inc +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/dev_start_guide.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/environment.yml +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/apply.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/apply.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/apply2.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/creating_a_numba_jax_op.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/ctype.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/extending_faq.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/extending_pytensor_solution_1.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/graph_rewriting.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/graphstructures.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/op.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/pics/symbolic_graph_opt.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/pics/symbolic_graph_unopt.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/pipeline.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/scan.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/tips.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/type.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/unittest.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/extending/using_params.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/faq.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/gallery/page_footer.md +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/gallery/rewrites/graph_rewrites.ipynb +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/gallery/scan/scan_tutorial.ipynb +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/generate_dtype_tensor_table.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/glossary.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/Elman_srnn.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/PyTensor.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/PyTensor_RGB.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/PyTensor_logo.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/binder.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/blocksparse.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/colab.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/github.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/lstm.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/lstm_memorycell.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/talk2010.gif +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/images/talk2010.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/internal/how_to_release.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/internal/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/internal/metadocumentation.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/introduction.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/debugmode.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/function.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/io.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/nanguardmode.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/opfromgraph.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/ops.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/profilemode.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/compile/shared.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/config.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/css/d3viz.css +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/js/d3viz.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/mlp.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/mlp.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/mlp2.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/mlp2.pdf +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/mlp2.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/ofg.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/examples/ofg2.html +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index.ipynb +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index_files/index_10_0.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index_files/index_11_0.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index_files/index_24_0.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/d3viz/index_files/index_25_0.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/gradient.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/features.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/fgraph.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/graph.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/op.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/replace.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/type.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/graph/utils.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/misc/pkl_utils.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/printing.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/scalar/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/scan.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/sparse/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/sparse/sandbox.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/basic.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/basic_opt.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/bcast.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/bcast.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/conv.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/elemwise.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/extra_ops.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/fft.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/functional.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/io.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/math_opt.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/nlinalg.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/plot_fft.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/random/distributions.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/slinalg.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/tensor/utils.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/library/typed_list.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/links.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/optimizations.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/pylintrc +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/robots.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/adding.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/adding_solution_1.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/aliasing.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/apply.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/apply.svg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/bcast.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/broadcasting.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/conditions.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/debug_faq.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/dlogistic.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/faq_tutorial.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/gradients.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/index.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/loading_and_saving.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/logistic.gp +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/logistic.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/loop.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/loop_solution_1.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/modes.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/modes_solution_1.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/multi_cores.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/nan_tutorial.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/pics/d3viz.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/pics/logreg_pydotprint_predict.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/pics/logreg_pydotprint_prediction.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/pics/logreg_pydotprint_train.png +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/printing_drawing.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/profiling.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/profiling_example.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/profiling_example_out.prof +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/shape_info.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/sparse.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/tutorial/symbolic_graphs.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/doc/user_guide.rst +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pyproject.toml +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/bin/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/bin/pytensor_cache.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/breakpoint.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/builders.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/compiledir.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/compilelock.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/debugmode.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/function/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/function/pfunc.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/function/types.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/io.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/mode.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/monitormode.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/nanguardmode.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/profiling.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/compile/sharedvalue.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/configdefaults.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/configparser.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/css/d3viz.css +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/d3viz.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/formatting.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/js/d3viz.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/gradient.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/destroyhandler.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/features.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/fg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/null_type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/replace.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/rewriting/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/rewriting/kanren.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/rewriting/unify.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/rewriting/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/graph/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/ifelse.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/basic.py +0 -0
- {pytensor-2.27.0/pytensor/graph/rewriting → pytensor-2.27.1/pytensor/link/c}/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/c_code/lazylinker_c.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/c_code/pytensor_mod_helper.h +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/cutils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/cvm.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/exceptions.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/interface.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/lazylinker_c.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/params_type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/c/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/blas.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/blockwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/einsum.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/elemwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/extra_ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/math.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/nlinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/pad.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/random.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/scalar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/scan.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/shape.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/slinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/sort.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/sparse.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/subtensor.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/dispatch/tensor_basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/jax/linker.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/blockwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/cython_support.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/extra_ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/nlinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/random.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/scalar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/scan.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/slinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/sparse.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/subtensor.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/tensor_basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/dispatch/vectorize_codegen.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/numba/linker.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/blas.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/blockwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/elemwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/extra_ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/math.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/nlinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/scalar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/shape.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/sort.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/dispatch/subtensor.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/pytorch/linker.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/link/vm.py +0 -0
- {pytensor-2.27.0/pytensor/link/c → pytensor-2.27.1/pytensor/misc}/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/check_blas.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/check_blas_many.sh +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/check_duplicate_key.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/elemwise_openmp_speedup.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/elemwise_time_test.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/frozendict.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/may_share_memory.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/ordered_set.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/misc/pkl_utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/printing.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/py.typed +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/raise_op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/c_code/Faddeeva.cc +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/c_code/Faddeeva.hh +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/c_code/gamma.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/c_code/incbet.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/loop.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/math.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scalar/sharedvar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/checkpoints.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/rewriting.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/scan_perform.pyx +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/scan_perform_ext.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/scan/views.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/rewriting.py +0 -0
- {pytensor-2.27.0/pytensor/misc → pytensor-2.27.1/pytensor/sparse/sandbox}/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/sandbox/sp.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/sandbox/sp2.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/sharedvar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/sparse/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/blas.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/blas_c.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/blas_scipy.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/blockwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/c_code/alt_blas_common.h +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/c_code/alt_blas_template.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/c_code/dimshuffle.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/conv/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/conv/abstract_conv.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/elemwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/elemwise_cgen.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/exceptions.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/extra_ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/fft.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/fourier.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/functional.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/inplace.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/interpolate.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/io.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/linalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/nlinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/pad.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/rewriting/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/rewriting/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/rewriting/jax.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/rewriting/numba.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/random/var.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/blas.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/blas_c.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/blas_scipy.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/blockwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/einsum.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/elemwise.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/extra_ops.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/jax.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/linalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/numba.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/ofg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/shape.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/special.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/subtensor.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/rewriting/uncanonicalize.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/shape.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/sharedvar.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/slinalg.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/sort.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/special.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/subtensor.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/type_other.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/var.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/variable.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/tensor/xlogx.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/typed_list/__init__.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/typed_list/basic.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/typed_list/rewriting.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/typed_list/type.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/updates.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor/utils.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor.egg-info/SOURCES.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor.egg-info/dependency_links.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor.egg-info/entry_points.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor.egg-info/requires.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/pytensor.egg-info/top_level.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/scripts/mypy-failing.txt +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/scripts/slowest_tests/update-slowest-times-issue.sh +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/setup.cfg +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/setup.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/link/c/c_code/test_cenum.h +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/link/c/c_code/test_quadratic_function.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/tensor/conv/c_code/corr3d_gemm.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/tensor/conv/c_code/corr_gemm.c +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_breakpoint.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_config.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_gradient.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_ifelse.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_printing.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_raise_op.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_rop.py +0 -0
- {pytensor-2.27.0 → pytensor-2.27.1}/tests/test_updates.py +0 -0
|
@@ -923,7 +923,7 @@ pre-defined macros. These section tags have no macros: ``init_code``,
|
|
|
923
923
|
discussed below.
|
|
924
924
|
|
|
925
925
|
* ``APPLY_SPECIFIC(str)`` which will automatically append a name
|
|
926
|
-
unique to the :ref:`
|
|
926
|
+
unique to the :ref:`apply` node that applies the `Op` at the end
|
|
927
927
|
of the provided ``str``. The use of this macro is discussed
|
|
928
928
|
further below.
|
|
929
929
|
|
|
@@ -994,7 +994,7 @@ Apply node in their own names to avoid conflicts between the different
|
|
|
994
994
|
versions of the apply-specific code. The code that wasn't
|
|
995
995
|
apply-specific was simply defined in the ``c_support_code`` method.
|
|
996
996
|
|
|
997
|
-
To make indentifiers that include the :ref:`
|
|
997
|
+
To make indentifiers that include the :ref:`apply` node name use the
|
|
998
998
|
``APPLY_SPECIFIC(str)`` macro. In the above example, this macro is
|
|
999
999
|
used when defining the functions ``vector_elemwise_mult`` and
|
|
1000
1000
|
``vector_times_vector`` as well as when calling function
|
|
@@ -7,7 +7,7 @@ Creating a new :class:`Op`: Python implementation
|
|
|
7
7
|
So suppose you have looked through the library documentation and you don't see
|
|
8
8
|
a function that does what you want.
|
|
9
9
|
|
|
10
|
-
If you can implement something in terms of an existing :ref:`
|
|
10
|
+
If you can implement something in terms of an existing :ref:`op`, you should do that.
|
|
11
11
|
Odds are your function that uses existing PyTensor expressions is short,
|
|
12
12
|
has no bugs, and potentially profits from rewrites that have already been
|
|
13
13
|
implemented.
|
|
@@ -200,7 +200,7 @@ input(s)'s memory). From there, go to the previous section.
|
|
|
200
200
|
certainly lead to erroneous computations.
|
|
201
201
|
|
|
202
202
|
You can often identify an incorrect `Op.view_map` or :attr:`Op.destroy_map`
|
|
203
|
-
by using :ref:`DebugMode
|
|
203
|
+
by using :ref:`DebugMode <debugmode>`.
|
|
204
204
|
|
|
205
205
|
.. note::
|
|
206
206
|
Consider using :class:`DebugMode` when developing
|
|
@@ -197,7 +197,7 @@ Want C speed without writing C code for your new Op? You can use Numba
|
|
|
197
197
|
to generate the C code for you! Here is an `example
|
|
198
198
|
Op <https://gist.github.com/nouiz/5492778#file-theano_op-py>`_ doing that.
|
|
199
199
|
|
|
200
|
-
..
|
|
200
|
+
.. _alternate_pytensor_types:
|
|
201
201
|
|
|
202
202
|
Alternate PyTensor Types
|
|
203
203
|
========================
|
|
@@ -20,6 +20,9 @@ PyTensor defines the following modes by name:
|
|
|
20
20
|
|
|
21
21
|
- ``'FAST_COMPILE'``: Apply just a few graph rewrites and only use Python implementations.
|
|
22
22
|
- ``'FAST_RUN'``: Apply all rewrites, and use C implementations where possible.
|
|
23
|
+
- ``NUMBA``: Apply all relevant related rewrites and compile the whole graph using Numba.
|
|
24
|
+
- ``JAX``: Apply all relevant rewrites and compile the whole graph using JAX.
|
|
25
|
+
- ``PYTORCH`` Apply all relevant rewrites and compile the whole graph using PyTorch compile.
|
|
23
26
|
- ``'DebugMode'``: A mode for debugging. See :ref:`DebugMode <debugmode>` for details.
|
|
24
27
|
- ``'NanGuardMode``: :ref:`Nan detector <nanguardmode>`
|
|
25
28
|
- ``'DEBUG_MODE'``: Deprecated. Use the string DebugMode.
|
|
@@ -28,6 +31,12 @@ The default mode is typically ``FAST_RUN``, but it can be controlled via the
|
|
|
28
31
|
configuration variable :attr:`config.mode`, which can be
|
|
29
32
|
overridden by passing the keyword argument to :func:`pytensor.function`.
|
|
30
33
|
|
|
34
|
+
For Numba, JAX, and PyTorch, we exclude rewrites that introduce C-only Ops,
|
|
35
|
+
as well as BLAS optimizations, as those are done automatically by the respective backends.
|
|
36
|
+
|
|
37
|
+
For JAX we also exclude fusion and inplace optimizations, as JAX does not support them
|
|
38
|
+
at the user level. They are performed automatically by JAX.
|
|
39
|
+
|
|
31
40
|
.. TODO::
|
|
32
41
|
|
|
33
42
|
For a finer level of control over which rewrites are applied, and whether
|
|
@@ -83,7 +83,7 @@ Low-level objects
|
|
|
83
83
|
.. automodule:: pytensor.tensor.random.op
|
|
84
84
|
:members: RandomVariable, default_rng
|
|
85
85
|
|
|
86
|
-
..automodule:: pytensor.tensor.random.type
|
|
86
|
+
.. automodule:: pytensor.tensor.random.type
|
|
87
87
|
:members: RandomType, RandomGeneratorType, random_generator_type
|
|
88
88
|
|
|
89
89
|
.. automodule:: pytensor.tensor.random.var
|
|
@@ -145,44 +145,64 @@ How do I configure/test my BLAS library
|
|
|
145
145
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
146
146
|
|
|
147
147
|
There are many ways to configure BLAS for PyTensor. This is done with the PyTensor
|
|
148
|
-
flags ``blas__ldflags`` (:ref:`libdoc_config`).
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
version of BLAS, in case you did not compile NumPy with a fast BLAS or if NumPy
|
|
152
|
-
was compiled with a static library of BLAS (the latter is not supported in
|
|
153
|
-
PyTensor).
|
|
148
|
+
flags ``blas__ldflags`` (:ref:`libdoc_config`). If not specified, PyTensor will
|
|
149
|
+
attempt to find a local BLAS library to link against, prioritizing specialized implementations.
|
|
150
|
+
The details can be found in :func:`pytensor.link.c.cmodule.default_blas_ldflags`.
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
Users can manually set the PyTensor flags ``blas__ldflags`` to link against a
|
|
153
|
+
specific version. This is useful even if the default version is the desired one,
|
|
154
|
+
as it will avoid the costly work of trying to find the best BLAS library at runtime.
|
|
158
155
|
|
|
159
|
-
The
|
|
160
|
-
|
|
161
|
-
|
|
156
|
+
The PyTensor flags can be set in a few ways:
|
|
157
|
+
|
|
158
|
+
1. In the ``${HOME}/.pytensorrc`` file.
|
|
162
159
|
|
|
163
160
|
.. code-block:: cfg
|
|
164
161
|
|
|
165
162
|
# other stuff can go here
|
|
166
163
|
[blas]
|
|
167
|
-
ldflags = -
|
|
164
|
+
ldflags = -llapack -lblas -lcblas # put your flags here
|
|
168
165
|
|
|
169
166
|
# other stuff can go here
|
|
170
167
|
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
2. In BASH before running your script:
|
|
169
|
+
|
|
170
|
+
.. code-block:: bash
|
|
171
|
+
|
|
172
|
+
export PYTENSOR_FLAGS="blas__ldflags='-llapack -lblas -lcblas'"
|
|
173
|
+
|
|
174
|
+
3. In an Ipython/Jupyter notebook before importing PyTensor:
|
|
175
|
+
|
|
176
|
+
.. code-block:: python
|
|
177
|
+
|
|
178
|
+
%set_env PYTENSOR_FLAGS=blas__ldflags='-llapack -lblas -lcblas'
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
4. In `pytensor.config` directly:
|
|
182
|
+
|
|
183
|
+
.. code-block:: python
|
|
184
|
+
|
|
185
|
+
import pytensor
|
|
186
|
+
pytensor.config.blas__ldflags = '-llapack -lblas -lcblas'
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
(For more information on the formatting of ``~/.pytensorrc`` and the
|
|
190
|
+
configuration options that you can put there, see :ref:`libdoc_config`.)
|
|
191
|
+
|
|
192
|
+
You can find the default BLAS library that PyTensor is linking against by
|
|
193
|
+
checking ``pytensor.config.blas__ldflags``
|
|
194
|
+
or running :func:`pytensor.link.c.cmodule.default_blas_ldflags`.
|
|
173
195
|
|
|
174
196
|
Here are some different way to configure BLAS:
|
|
175
197
|
|
|
176
|
-
0) Do nothing and use the default config
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
static library).
|
|
198
|
+
0) Do nothing and use the default config.
|
|
199
|
+
This will usually work great for installation via conda/mamba/pixi (conda-forge channel).
|
|
200
|
+
It will usually fail to link altogether for installation via pip.
|
|
180
201
|
|
|
181
202
|
1) Disable the usage of BLAS and fall back on NumPy for dot products. To do
|
|
182
|
-
this, set the value of ``blas__ldflags`` as the empty string
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
directly).
|
|
203
|
+
this, set the value of ``blas__ldflags`` as the empty string.
|
|
204
|
+
Depending on the kind of matrix operations your PyTensor code performs,
|
|
205
|
+
this might slow some things down (vs. linking with BLAS directly).
|
|
186
206
|
|
|
187
207
|
2) You can install the default (reference) version of BLAS if the NumPy version
|
|
188
208
|
(against which PyTensor links) does not work. If you have root or sudo access in
|
|
@@ -208,10 +228,29 @@ correctly (for example, for MKL this might be ``-lmkl -lguide -lpthread`` or
|
|
|
208
228
|
``-lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core -lguide -liomp5 -lmkl_mc
|
|
209
229
|
-lpthread``).
|
|
210
230
|
|
|
231
|
+
5) Use another backend such as Numba or JAX that perform their own BLAS optimizations,
|
|
232
|
+
by setting the configuration mode to ``"NUMBA"`` or ``"JAX"`` and making sure those packages are installed.
|
|
233
|
+
This configuration mode can be set in all the ways that the BLAS flags can be set, described above.
|
|
234
|
+
|
|
235
|
+
Alternatively, you can pass `mode='NUMBA'` when compiling individual PyTensor functions without changing the default.
|
|
236
|
+
or use the ``config.change_flags`` context manager.
|
|
237
|
+
|
|
238
|
+
.. code-block:: python
|
|
239
|
+
|
|
240
|
+
from pytensor import function, config
|
|
241
|
+
from pytensor.tensor import matrix
|
|
242
|
+
|
|
243
|
+
x = matrix('x')
|
|
244
|
+
y = x @ x.T
|
|
245
|
+
f = function([x], y, mode='NUMBA')
|
|
246
|
+
|
|
247
|
+
with config.change_flags(mode='NUMBA'):
|
|
248
|
+
# compiling function that benefits from BLAS using NUMBA
|
|
249
|
+
f = function([x], y)
|
|
250
|
+
|
|
211
251
|
.. note::
|
|
212
252
|
|
|
213
|
-
Make sure your BLAS
|
|
214
|
-
libraries are available as dynamically-loadable libraries.
|
|
253
|
+
Make sure your BLAS libraries are available as dynamically-loadable libraries.
|
|
215
254
|
ATLAS is often installed only as a static library. PyTensor is not able to
|
|
216
255
|
use this static library. Your ATLAS installation might need to be modified
|
|
217
256
|
to provide dynamically loadable libraries. (On Linux this
|
|
@@ -267,7 +306,7 @@ configuration information. Then, it will print the running time of the same
|
|
|
267
306
|
benchmarks for your installation. Try to find a CPU similar to yours in
|
|
268
307
|
the table, and check that the single-threaded timings are roughly the same.
|
|
269
308
|
|
|
270
|
-
PyTensor should link to a parallel version of
|
|
309
|
+
PyTensor should link to a parallel version of BLAS and use all cores
|
|
271
310
|
when possible. By default it should use all cores. Set the environment
|
|
272
311
|
variable "OMP_NUM_THREADS=N" to specify to use N threads.
|
|
273
312
|
|
|
@@ -347,15 +347,7 @@ afterwards compile this expression to get functions,
|
|
|
347
347
|
using pseudo-random numbers is not as straightforward as it is in
|
|
348
348
|
NumPy, though also not too complicated.
|
|
349
349
|
|
|
350
|
-
The
|
|
351
|
-
to put random variables in your graph. PyTensor will allocate a NumPy
|
|
352
|
-
`RandomStream` object (a random number generator) for each such
|
|
353
|
-
variable, and draw from it as necessary. We will call this sort of
|
|
354
|
-
sequence of random numbers a *random stream*. *Random streams* are at
|
|
355
|
-
their core shared variables, so the observations on shared variables
|
|
356
|
-
hold here as well. PyTensor's random objects are defined and implemented in
|
|
357
|
-
:ref:`RandomStream<libdoc_tensor_random_utils>` and, at a lower level,
|
|
358
|
-
in :ref:`RandomVariable<libdoc_tensor_random_basic>`.
|
|
350
|
+
The general user-facing API is documented in :ref:`RandomStream<libdoc_tensor_random_basic>`
|
|
359
351
|
|
|
360
352
|
For a more technical explanation of how PyTensor implements random variables see :ref:`prng`.
|
|
361
353
|
|
|
@@ -31,8 +31,8 @@ In the first line np.random.default_rng(seed) creates a random Generator.
|
|
|
31
31
|
>>> rng # doctest: +SKIP
|
|
32
32
|
Generator(PCG64) at 0x7F6C04535820
|
|
33
33
|
|
|
34
|
-
Every
|
|
35
|
-
|
|
34
|
+
Every NumPy Generator holds a BitGenerator, which is able to generate high-quality sequences of pseudo random bits.
|
|
35
|
+
NumPy generators' methods convert these sequences of bits into sequences of numbers that follow a specific statistical distribution.
|
|
36
36
|
For more details, you can read `NumPy random sampling documentation <https://numpy.org/doc/stable/reference/random>`_.
|
|
37
37
|
|
|
38
38
|
>>> rng.bit_generator # doctest: +SKIP
|
|
@@ -47,6 +47,7 @@ For more details, you can read `NumPy random sampling documentation <https://num
|
|
|
47
47
|
|
|
48
48
|
When we call rng.uniform(size=2), the Generator class requested a new array of pseudo random bits (state) from the BitGenerator,
|
|
49
49
|
and used a deterministic mapping function to convert those into a float64 numbers.
|
|
50
|
+
|
|
50
51
|
It did this twice, because we requested two draws via the size argument.
|
|
51
52
|
In the long-run this deterministic mapping function should produce draws that are statistically indistinguishable from a true uniform distribution.
|
|
52
53
|
|
|
@@ -71,7 +72,7 @@ array([0.033, 0.972, 0.459, 0.71 , 0.765])
|
|
|
71
72
|
SciPy
|
|
72
73
|
-----
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
SciPy wraps these NumPy routines in a slightly different API.
|
|
75
76
|
|
|
76
77
|
>>> import scipy.stats as st
|
|
77
78
|
>>> rng = np.random.default_rng(seed=123)
|
|
@@ -82,7 +83,7 @@ PyTensor
|
|
|
82
83
|
--------
|
|
83
84
|
|
|
84
85
|
PyTensor does not implement its own bit/generators methods.
|
|
85
|
-
Just like
|
|
86
|
+
Just like SciPy, it borrows NumPy routines directly.
|
|
86
87
|
|
|
87
88
|
The low-level API of PyTensor RNGs is similar to that of SciPy,
|
|
88
89
|
whereas the higher-level API of RandomStreams is more like that of NumPy.
|
|
@@ -95,20 +96,19 @@ We will look at RandomStreams shortly, but we will start with the low-level API.
|
|
|
95
96
|
>>> x = pt.random.uniform(size=2, rng=rng)
|
|
96
97
|
>>> f = pytensor.function([rng], x)
|
|
97
98
|
|
|
98
|
-
We created a function that takes a
|
|
99
|
+
We created a function that takes a NumPy RandomGenerator and returns two uniform draws. Let's evaluate it
|
|
99
100
|
|
|
100
101
|
>>> rng_val = np.random.default_rng(123)
|
|
101
102
|
>>> print(f(rng_val), f(rng_val))
|
|
102
103
|
[0.68235186 0.05382102] [0.68235186 0.05382102]
|
|
103
104
|
|
|
104
|
-
The first numbers were exactly the same as the
|
|
105
|
+
The first numbers were exactly the same as the NumPy and SciPy calls, because we are using the very same routines.
|
|
105
106
|
|
|
106
107
|
Perhaps surprisingly, we got the same results when we called the function the second time!
|
|
107
108
|
This is because PyTensor functions do not hold an internal state and do not modify inputs inplace unless requested to.
|
|
108
109
|
|
|
109
|
-
We made sure that the rng_val was not modified when calling our
|
|
110
|
-
This may feel inefficient (and it is), but PyTensor is built on a pure functional approach, which is not allowed to have side-effects
|
|
111
|
-
(such as changing global variables) by default.
|
|
110
|
+
We made sure that the rng_val was not modified when calling our PyTensor function, by copying it before using it.
|
|
111
|
+
This may feel inefficient (and it is), but PyTensor is built on a pure functional approach, which is not allowed to have side-effects by default.
|
|
112
112
|
|
|
113
113
|
We will later see how we can get around this issue by making the inputs mutable or using shared variables with explicit update rules.
|
|
114
114
|
|
|
@@ -129,8 +129,8 @@ In this case we had to advance it twice to get two completely new draws, because
|
|
|
129
129
|
But other distributions could need more states for a single draw, or they could be clever and reuse the same state for multiple draws.
|
|
130
130
|
|
|
131
131
|
Because it is not in generally possible to know how much one should modify the generator's bit generator,
|
|
132
|
-
PyTensor RandomVariables actually return the
|
|
133
|
-
This
|
|
132
|
+
PyTensor RandomVariables actually return the used generator as a hidden output.
|
|
133
|
+
This generator can be safely used again because it contains the bit generator that was already modified when taking draws.
|
|
134
134
|
|
|
135
135
|
>>> next_rng, x = x.owner.outputs
|
|
136
136
|
>>> next_rng.type, x.type
|
|
@@ -148,7 +148,6 @@ uniform_rv{"(),()->()"}.0 [id A] <RandomGeneratorType> 'next_rng'
|
|
|
148
148
|
└─ 1.0 [id G] <Scalar(float32, shape=())>
|
|
149
149
|
uniform_rv{"(),()->()"}.1 [id A] <Vector(float64, shape=(2,))> 'x'
|
|
150
150
|
└─ ···
|
|
151
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
152
151
|
|
|
153
152
|
We can see the single node with [id A], has two outputs, which we named next_rng and x. By default only the second output x is given to the user directly, and the other is "hidden".
|
|
154
153
|
|
|
@@ -226,14 +225,14 @@ This is exactly what RandomStream does behind the scenes
|
|
|
226
225
|
>>> x.owner.inputs[0], x.owner.inputs[0].default_update # doctest: +SKIP
|
|
227
226
|
(RNG(<Generator(PCG64) at 0x7FA45F4A3760>), uniform_rv{"(),()->()"}.0)
|
|
228
227
|
|
|
229
|
-
From the example here, you can see that RandomStream uses a NumPy-like API in contrast to
|
|
230
|
-
the SciPy-like API of `pytensor.tensor.random`. Full documentation can be found at
|
|
231
|
-
:doc:`../library/tensor/random/basic`.
|
|
232
|
-
|
|
233
228
|
>>> f = pytensor.function([], x)
|
|
234
229
|
>>> print(f(), f(), f())
|
|
235
230
|
0.19365083425294516 0.7541389670292019 0.2762903411491048
|
|
236
231
|
|
|
232
|
+
From the example here, you can see that RandomStream uses a NumPy-like API in contrast to
|
|
233
|
+
the SciPy-like API of `pytensor.tensor.random`. Full documentation can be found at
|
|
234
|
+
:doc:`libdoc_tensor_random_basic`.
|
|
235
|
+
|
|
237
236
|
Shared RNGs are created by default
|
|
238
237
|
----------------------------------
|
|
239
238
|
|
|
@@ -279,7 +278,7 @@ RandomStreams provide a helper method to achieve the same
|
|
|
279
278
|
Inplace optimization
|
|
280
279
|
====================
|
|
281
280
|
|
|
282
|
-
As mentioned
|
|
281
|
+
As mentioned, RandomVariable Ops default to making a copy of the input RNG before using it, which can be quite slow.
|
|
283
282
|
|
|
284
283
|
>>> rng = np.random.default_rng(123)
|
|
285
284
|
>>> rng_shared = pytensor.shared(rng, name="rng")
|
|
@@ -291,13 +290,13 @@ uniform_rv{"(),()->()"}.1 [id A] 'x' 0
|
|
|
291
290
|
├─ NoneConst{None} [id C]
|
|
292
291
|
├─ 0.0 [id D]
|
|
293
292
|
└─ 1.0 [id E]
|
|
294
|
-
|
|
293
|
+
|
|
295
294
|
|
|
296
295
|
>>> %timeit f() # doctest: +SKIP
|
|
297
|
-
|
|
296
|
+
81.8 µs ± 15.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
|
|
298
297
|
|
|
299
298
|
>>> %timeit rng.uniform() # doctest: +SKIP
|
|
300
|
-
|
|
299
|
+
2.15 µs ± 63.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
|
|
301
300
|
|
|
302
301
|
Like other PyTensor operators, RandomVariable's can be given permission to modify inputs inplace during their operation.
|
|
303
302
|
|
|
@@ -307,16 +306,6 @@ If the flag is set, the RNG will not be copied before taking random draws.
|
|
|
307
306
|
>>> x.owner.op.inplace
|
|
308
307
|
False
|
|
309
308
|
|
|
310
|
-
This flag is printed as the last argument of the Op in the `dprint`
|
|
311
|
-
|
|
312
|
-
>>> pytensor.dprint(x) # doctest: +SKIP
|
|
313
|
-
uniform_rv{"(),()->()"}.1 [id A] 'x' 0
|
|
314
|
-
├─ rng [id B]
|
|
315
|
-
├─ NoneConst{None} [id C]
|
|
316
|
-
├─ 0.0 [id D]
|
|
317
|
-
└─ 1.0 [id E]
|
|
318
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
319
|
-
|
|
320
309
|
For illustration purposes, we will subclass the Uniform Op class and set inplace to True by default.
|
|
321
310
|
|
|
322
311
|
Users should never do this directly!
|
|
@@ -336,27 +325,21 @@ uniform_rv{"(),()->()"}.1 [id A] d={0: [0]} 0
|
|
|
336
325
|
├─ NoneConst{None} [id C]
|
|
337
326
|
├─ 0.0 [id D]
|
|
338
327
|
└─ 1.0 [id E]
|
|
339
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
340
328
|
|
|
341
|
-
The destroy map annotation tells us that the first output of the x variable is allowed to
|
|
329
|
+
The destroy map annotation tells us that the first output of the x variable is allowed to modify the first input.
|
|
342
330
|
|
|
343
331
|
>>> %timeit inplace_f() # doctest: +SKIP
|
|
344
|
-
|
|
332
|
+
9.71 µs ± 2.06 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
|
|
345
333
|
|
|
346
|
-
Performance is now much closer to calling
|
|
334
|
+
Performance is now much closer to calling NumPy directly, with a small overhead introduced by the PyTensor function.
|
|
347
335
|
|
|
348
336
|
The `random_make_inplace <https://github.com/pymc-devs/pytensor/blob/3fcf6369d013c597a9c964b2400a3c5e20aa8dce/pytensor/tensor/random/rewriting/basic.py#L42-L52>`_
|
|
349
337
|
rewrite automatically replaces RandomVariable Ops by their inplace counterparts, when such operation is deemed safe. This happens when:
|
|
350
338
|
|
|
351
339
|
#. An input RNG is flagged as `mutable` and is used in not used anywhere else.
|
|
352
|
-
#. A RNG is created intermediately and
|
|
340
|
+
#. A RNG is created intermediately and not used anywhere else.
|
|
353
341
|
|
|
354
|
-
The first case is true when a users uses the `mutable` `kwarg` directly
|
|
355
|
-
when a shared RNG is used and a (default or manual) update expression is given.
|
|
356
|
-
In this case, a RandomVariable is allowed to modify the RNG because the shared variable holding it will be rewritten anyway.
|
|
357
|
-
|
|
358
|
-
The second case is not very common, because RNGs are not usually chained across multiple RandomVariable Ops.
|
|
359
|
-
See more details in the next section.
|
|
342
|
+
The first case is true when a users uses the `mutable` `kwarg` directly.
|
|
360
343
|
|
|
361
344
|
>>> from pytensor.compile.io import In
|
|
362
345
|
>>> rng = pt.random.type.RandomGeneratorType()("rng")
|
|
@@ -371,7 +354,9 @@ uniform_rv{"(),()->()"}.1 [id A] d={0: [0]} 0
|
|
|
371
354
|
├─ NoneConst{None} [id C]
|
|
372
355
|
├─ 0.0 [id D]
|
|
373
356
|
└─ 1.0 [id E]
|
|
374
|
-
|
|
357
|
+
|
|
358
|
+
Or, much more commonly, when a shared RNG is used and a (default or manual) update expression is given.
|
|
359
|
+
In this case, a RandomVariable is allowed to modify the RNG because the shared variable holding it will be rewritten anyway.
|
|
375
360
|
|
|
376
361
|
>>> rng = pytensor.shared(np.random.default_rng(), name="rng")
|
|
377
362
|
>>> next_rng, x = pt.random.uniform(rng=rng).owner.outputs
|
|
@@ -385,7 +370,9 @@ uniform_rv{"(),()->()"}.1 [id A] d={0: [0]} 0
|
|
|
385
370
|
└─ 1.0 [id E]
|
|
386
371
|
uniform_rv{"(),()->()"}.0 [id A] d={0: [0]} 0
|
|
387
372
|
└─ ···
|
|
388
|
-
|
|
373
|
+
|
|
374
|
+
The second case is not very common, because RNGs are not usually chained across multiple RandomVariable Ops.
|
|
375
|
+
See more details in the next section.
|
|
389
376
|
|
|
390
377
|
Multiple random variables
|
|
391
378
|
=========================
|
|
@@ -420,7 +407,6 @@ normal_rv{"(),()->()"}.0 [id A] <RandomGeneratorType> 'next_rng_x' 0
|
|
|
420
407
|
└─ ···
|
|
421
408
|
normal_rv{"(),()->()"}.0 [id F] <RandomGeneratorType> 'next_rng_y' 1
|
|
422
409
|
└─ ···
|
|
423
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
424
410
|
|
|
425
411
|
>>> f(), f(), f()
|
|
426
412
|
([array(-9.8912135), array(-9.80160951)],
|
|
@@ -450,7 +436,6 @@ normal_rv{"(),()->()"}.0 [id A] <RandomGeneratorType> 0
|
|
|
450
436
|
└─ ···
|
|
451
437
|
normal_rv{"(),()->()"}.0 [id F] <RandomGeneratorType> 1
|
|
452
438
|
└─ ···
|
|
453
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
454
439
|
|
|
455
440
|
>>> f(), f(), f()
|
|
456
441
|
([array(-5.81223492), array(-5.85081162)],
|
|
@@ -460,15 +445,15 @@ normal_rv{"(),()->()"}.0 [id F] <RandomGeneratorType> 1
|
|
|
460
445
|
We could have used a single rng.
|
|
461
446
|
|
|
462
447
|
>>> rng_x = pytensor.shared(np.random.default_rng(seed=123), name="rng_x")
|
|
463
|
-
>>> next_rng_x, x = pt.random.normal(loc=0, scale=1, rng=
|
|
448
|
+
>>> next_rng_x, x = pt.random.normal(loc=0, scale=1, rng=rng_x).owner.outputs
|
|
464
449
|
>>> next_rng_x.name = "next_rng_x"
|
|
465
450
|
>>> next_rng_y, y = pt.random.normal(loc=100, scale=1, rng=next_rng_x).owner.outputs
|
|
466
451
|
>>> next_rng_y.name = "next_rng_y"
|
|
467
452
|
>>>
|
|
468
|
-
>>> f = pytensor.function([], [x, y], updates={
|
|
453
|
+
>>> f = pytensor.function([], [x, y], updates={rng_x: next_rng_y})
|
|
469
454
|
>>> pytensor.dprint(f, print_type=True) # doctest: +SKIP
|
|
470
455
|
normal_rv{"(),()->()"}.1 [id A] <Scalar(float64, shape=())> 0
|
|
471
|
-
├─
|
|
456
|
+
├─ rng_x [id B] <RandomGeneratorType>
|
|
472
457
|
├─ NoneConst{None} [id C] <NoneTypeT>
|
|
473
458
|
├─ 0 [id D] <Scalar(int8, shape=())>
|
|
474
459
|
└─ 1 [id E] <Scalar(int8, shape=())>
|
|
@@ -480,24 +465,23 @@ normal_rv{"(),()->()"}.1 [id F] <Scalar(float64, shape=())> 1
|
|
|
480
465
|
└─ 1 [id E] <Scalar(int8, shape=())>
|
|
481
466
|
normal_rv{"(),()->()"}.0 [id F] <RandomGeneratorType> 'next_rng_y' 1
|
|
482
467
|
└─ ···
|
|
483
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
484
468
|
|
|
485
469
|
>>> f(), f()
|
|
486
|
-
([array(0.
|
|
487
|
-
[array(
|
|
470
|
+
([array(-0.98912135), array(99.63221335)],
|
|
471
|
+
[array(1.28792526), array(100.19397442)])
|
|
488
472
|
|
|
489
|
-
It works, but that graph is slightly unorthodox in
|
|
473
|
+
It works, but that graph is slightly unorthodox in PyTensor.
|
|
490
474
|
|
|
491
|
-
One practical reason is that it is more difficult to define the correct update expression for the shared RNG variable.
|
|
475
|
+
One practical reason why, is that it is more difficult to define the correct update expression for the shared RNG variable.
|
|
492
476
|
|
|
493
|
-
One techincal reason is that it makes rewrites more challenging in cases where RandomVariables could otherwise be manipulated independently.
|
|
477
|
+
One techincal reason why, is that it makes rewrites more challenging in cases where RandomVariables could otherwise be manipulated independently.
|
|
494
478
|
|
|
495
479
|
Creating multiple RNG variables
|
|
496
480
|
-------------------------------
|
|
497
481
|
|
|
498
482
|
RandomStreams generate high quality seeds for multiple variables, following the NumPy best practices https://numpy.org/doc/stable/reference/random/parallel.html#parallel-random-number-generation.
|
|
499
483
|
|
|
500
|
-
Users who
|
|
484
|
+
Users who sidestep RandomStreams, either by creating their own RNGs or relying on RandomVariable's default shared RNGs, should follow the same practice!
|
|
501
485
|
|
|
502
486
|
Random variables in inner graphs
|
|
503
487
|
================================
|
|
@@ -629,7 +613,7 @@ RNGs in Scan are only supported via shared variables in non-sequences at the mom
|
|
|
629
613
|
>>> print(err)
|
|
630
614
|
Tensor type field must be a TensorType; found <class 'pytensor.tensor.random.type.RandomGeneratorType'>.
|
|
631
615
|
|
|
632
|
-
In the future,
|
|
616
|
+
In the future, RandomGenerator variables may be allowed as explicit recurring states, rendering the internal use of updates optional or unnecessary
|
|
633
617
|
|
|
634
618
|
OpFromGraph
|
|
635
619
|
-----------
|
|
@@ -671,7 +655,7 @@ Other backends (and their limitations)
|
|
|
671
655
|
Numba
|
|
672
656
|
-----
|
|
673
657
|
|
|
674
|
-
NumPy random
|
|
658
|
+
NumPy random generators can be natively used with the Numba backend.
|
|
675
659
|
|
|
676
660
|
>>> rng = pytensor.shared(np.random.default_rng(123), name="randomstate_rng")
|
|
677
661
|
>>> x = pt.random.normal(rng=rng)
|
|
@@ -692,7 +676,6 @@ Inner graphs:
|
|
|
692
676
|
└─ *4-<Scalar(float32, shape=())> [id K] <Scalar(float32, shape=())>
|
|
693
677
|
← normal_rv{"(),()->()"}.1 [id G] <Scalar(float64, shape=())>
|
|
694
678
|
└─ ···
|
|
695
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
696
679
|
|
|
697
680
|
>>> print(numba_fn(), numba_fn())
|
|
698
681
|
-0.9891213503478509 -0.9891213503478509
|
|
@@ -700,11 +683,11 @@ Inner graphs:
|
|
|
700
683
|
JAX
|
|
701
684
|
---
|
|
702
685
|
|
|
703
|
-
JAX uses a different type of PRNG than those of
|
|
686
|
+
JAX uses a different type of PRNG than those of NumPy. This means that the standard shared RNGs cannot be used directly in graphs transpiled to JAX.
|
|
704
687
|
|
|
705
|
-
Instead a copy of the Shared RNG variable is made, and its bit generator state is
|
|
688
|
+
Instead a copy of the Shared RNG variable is made, and its bit generator state is expanded with a jax_state entry. This is what's actually used by the JAX random variables.
|
|
706
689
|
|
|
707
|
-
In general, update rules are still respected, but they won't
|
|
690
|
+
In general, update rules are still respected, but they won't update/rely on the original shared variable.
|
|
708
691
|
|
|
709
692
|
>>> import jax
|
|
710
693
|
>>> rng = pytensor.shared(np.random.default_rng(123), name="rng")
|
|
@@ -718,7 +701,6 @@ uniform_rv{"(),()->()"}.1 [id A] <Scalar(float64, shape=())> 0
|
|
|
718
701
|
└─ 1.0 [id E] <Scalar(float32, shape=())>
|
|
719
702
|
uniform_rv{"(),()->()"}.0 [id A] <RandomGeneratorType> 0
|
|
720
703
|
└─ ···
|
|
721
|
-
<ipykernel.iostream.OutStream at 0x7fa5d3a475e0>
|
|
722
704
|
|
|
723
705
|
>>> print(jax_fn(), jax_fn())
|
|
724
706
|
[Array(0.07577298, dtype=float64)] [Array(0.09217023, dtype=float64)]
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-02-03T19:06:21+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.27.
|
|
14
|
+
"full-revisionid": "c22e79e1bbf54deb7043a3a778b6e91295d25e07",
|
|
15
|
+
"version": "2.27.1"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -35,6 +35,7 @@ class RewriteDatabase:
|
|
|
35
35
|
rewriter: Union["RewriteDatabase", RewritesType],
|
|
36
36
|
*tags: str,
|
|
37
37
|
use_db_name_as_tag=True,
|
|
38
|
+
overwrite_existing=False,
|
|
38
39
|
):
|
|
39
40
|
"""Register a new rewriter to the database.
|
|
40
41
|
|
|
@@ -56,7 +57,8 @@ class RewriteDatabase:
|
|
|
56
57
|
``local_remove_all_assert``. Setting `use_db_name_as_tag` to
|
|
57
58
|
``False`` removes that behavior. This means that only the rewrite's name
|
|
58
59
|
and/or its tags will enable it.
|
|
59
|
-
|
|
60
|
+
overwrite_existing:
|
|
61
|
+
Overwrite the existing rewriter with a new one having the same name
|
|
60
62
|
"""
|
|
61
63
|
if not isinstance(
|
|
62
64
|
rewriter,
|
|
@@ -66,22 +68,27 @@ class RewriteDatabase:
|
|
|
66
68
|
):
|
|
67
69
|
raise TypeError(f"{rewriter} is not a valid rewrite type.")
|
|
68
70
|
|
|
69
|
-
if name in self.__db__:
|
|
70
|
-
raise ValueError(f"The tag '{name}' is already present in the database.")
|
|
71
|
-
|
|
72
71
|
if use_db_name_as_tag:
|
|
73
72
|
if self.name is not None:
|
|
74
73
|
tags = (*tags, self.name)
|
|
75
74
|
|
|
76
75
|
rewriter.name = name
|
|
77
|
-
|
|
78
|
-
#
|
|
79
|
-
if
|
|
80
|
-
raise ValueError(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
|
|
77
|
+
# if tag collides with name
|
|
78
|
+
if name in self.__db__ and name not in self._names:
|
|
79
|
+
raise ValueError(f"The tag '{name}' is already present in the database.")
|
|
80
|
+
|
|
81
|
+
if name in self.__db__ or rewriter.name in self.__db__:
|
|
82
|
+
if overwrite_existing:
|
|
83
|
+
self.remove_tags(name, *tags)
|
|
84
|
+
old_rewriter = self.__db__[name].pop()
|
|
85
|
+
self._names.remove(name)
|
|
86
|
+
self.__db__[old_rewriter.__class__.__name__].remove(old_rewriter)
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"The tag '{name}' is already present in the database."
|
|
90
|
+
)
|
|
91
|
+
|
|
85
92
|
self.__db__[name] = OrderedSet([rewriter])
|
|
86
93
|
self._names.add(name)
|
|
87
94
|
self.__db__[rewriter.__class__.__name__].add(rewriter)
|