pytensor 2.17.4__tar.gz → 2.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytensor-2.17.4 → pytensor-2.18.0}/PKG-INFO +1 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/random/basic.rst +0 -3
- {pytensor-2.17.4 → pytensor-2.18.0}/pyproject.toml +1 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/_version.py +3 -3
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/gradient.py +1 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/__init__.py +1 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/replace.py +14 -4
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/cmodule.py +12 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/scalar.py +70 -40
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/random.py +0 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/math.py +53 -4
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/__init__.py +1 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/blockwise.py +23 -57
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/elemwise.py +2 -3
- pytensor-2.18.0/pytensor/tensor/functional.py +125 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/math.py +6 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/basic.py +16 -35
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/rewriting/jax.py +0 -13
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/math.py +22 -2
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/shape.py +59 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/utils.py +38 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/variable.py +36 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/PKG-INFO +1 -1
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/SOURCES.txt +1 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/LICENSE.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/MANIFEST.in +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/README.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/bin/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/bin/pytensor-cache +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/bin/pytensor_cache.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/.templates/PLACEHOLDER +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/.templates/layout.html +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/LICENSE.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/README.md +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/acknowledgement.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/bcast.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/bcast.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/conf.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/core_development_guide.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/css.inc +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/dev_start_guide.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/environment.yml +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/apply.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/apply.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/apply2.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/creating_a_c_op.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/creating_a_numba_jax_op.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/creating_an_op.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/ctype.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/extending_faq.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/extending_pytensor_solution_1.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/graph_rewriting.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/graphstructures.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/inplace.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/op.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/other_ops.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/pics/symbolic_graph_opt.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/pics/symbolic_graph_unopt.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/pipeline.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/scan.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/tips.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/type.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/unittest.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/extending/using_params.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/faq.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/generate_dtype_tensor_table.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/glossary.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/Elman_srnn.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/PyTensor_RGB.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/blocksparse.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/lstm.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/lstm_memorycell.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/talk2010.gif +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/images/talk2010.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/install.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/internal/how_to_release.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/internal/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/internal/metadocumentation.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/introduction.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/debugmode.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/function.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/io.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/mode.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/nanguardmode.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/opfromgraph.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/ops.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/profilemode.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/compile/shared.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/config.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/css/d3viz.css +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/js/d3viz.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/mlp.html +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/mlp.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/mlp2.html +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/mlp2.pdf +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/mlp2.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/ofg.html +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/examples/ofg2.html +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index.ipynb +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index_files/index_10_0.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index_files/index_11_0.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index_files/index_24_0.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/d3viz/index_files/index_25_0.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/gradient.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/features.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/fgraph.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/graph.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/op.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/type.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/graph/utils.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/misc/pkl_utils.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/printing.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/sandbox/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/sandbox/linalg.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/scalar/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/scan.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/sparse/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/sparse/sandbox.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/basic.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/basic_opt.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/bcast.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/bcast.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/conv.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/elemwise.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/extra_ops.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/fft.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/io.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/math_opt.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/nlinalg.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/plot_fft.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/random/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/random/utils.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/slinalg.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/tensor/utils.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/library/typed_list.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/links.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/optimizations.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/pylintrc +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/ccodegen.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/compilation.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/debugging_with_stepmode.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/elemwise_compiler.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/function.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/functional.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/how_to_make_ops.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/index2.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/interactive_debugger.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/logistic_regression_example.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/performance.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/randomnumbers.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/rethinkccodegen.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/sandbox.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/software.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/sparse.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/sandbox/tensoroptools.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/scripts/docgen.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/troubleshooting.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/adding.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/adding_solution_1.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/aliasing.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/apply.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/apply.svg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/bcast.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/broadcasting.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/conditions.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/debug_faq.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/dlogistic.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/examples.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/faq_tutorial.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/gradients.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/index.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/loading_and_saving.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/logistic.gp +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/logistic.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/loop.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/loop_solution_1.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/modes.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/modes_solution_1.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/multi_cores.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/nan_tutorial.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/pics/d3viz.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/pics/logreg_pydotprint_predict.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/pics/logreg_pydotprint_prediction.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/pics/logreg_pydotprint_train.png +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/printing_drawing.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/profiling.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/profiling_example.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/profiling_example_out.prof +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/shape_info.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/sparse.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/tutorial/symbolic_graphs.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/doc/user_guide.rst +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/bin/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/bin/pytensor_cache.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/breakpoint.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/builders.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/compiledir.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/compilelock.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/debugmode.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/function/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/function/pfunc.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/function/types.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/io.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/mode.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/monitormode.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/nanguardmode.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/ops.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/profiling.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/compile/sharedvalue.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/configdefaults.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/configparser.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/css/d3-context-menu.css +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/css/d3viz.css +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/d3viz.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/formatting.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/js/d3-context-menu.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/js/d3.v3.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/js/d3viz.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/js/dagre-d3.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/d3viz/js/graphlib-dot.min.js +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/destroyhandler.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/features.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/fg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/null_type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/db.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/kanren.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/unify.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/rewriting/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/graph/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/ifelse.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/c_code/lazylinker_c.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/c_code/pytensor_mod_helper.h +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/cutils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/cvm.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/exceptions.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/interface.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/lazylinker_c.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/params_type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/c/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/blockwise.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/elemwise.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/extra_ops.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/nlinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/random.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/scan.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/shape.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/slinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/sparse.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/subtensor.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/dispatch/tensor_basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/jax/linker.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/cython_support.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/elemwise.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/elemwise_codegen.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/extra_ops.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/nlinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/scalar.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/scan.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/slinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/sparse.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/dispatch/tensor_basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/numba/linker.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/link/vm.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/check_blas.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/check_blas_many.sh +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/check_duplicate_key.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/elemwise_openmp_speedup.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/elemwise_time_test.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/frozendict.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/may_share_memory.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/ordered_set.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/pkl_utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/misc/safe_asarray.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/printing.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/py.typed +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/raise_op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/c_code/Faddeeva.cc +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/c_code/Faddeeva.hh +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/c_code/gamma.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/loop.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scalar/sharedvar.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/checkpoints.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/rewriting.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/scan_perform.pyx +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/scan_perform_ext.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/scan/views.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/rewriting.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/sandbox/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/sandbox/sp.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/sandbox/sp2.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/sharedvar.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/sparse/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/blas.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/blas_c.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/blas_headers.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/blas_scipy.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/c_code/alt_blas_common.h +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/c_code/alt_blas_template.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/c_code/dimshuffle.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/conv/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/conv/abstract_conv.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/elemwise_cgen.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/exceptions.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/extra_ops.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/fft.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/fourier.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/inplace.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/io.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/linalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/nlinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/rewriting/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/rewriting/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/random/var.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/blas.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/blas_c.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/blas_scipy.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/blockwise.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/elemwise.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/extra_ops.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/jax.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/linalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/shape.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/special.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/subtensor.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/rewriting/uncanonicalize.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/sharedvar.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/slinalg.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/sort.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/special.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/subtensor.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/type_other.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/var.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/tensor/xlogx.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/typed_list/__init__.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/typed_list/basic.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/typed_list/rewriting.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/typed_list/type.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/updates.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/utils.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor/version.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/dependency_links.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/entry_points.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/requires.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/pytensor.egg-info/top_level.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/scripts/downstream_pr.sh +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/scripts/mypy-failing.txt +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/scripts/upstream_pr.sh +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/setup.cfg +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/setup.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/link/c/c_code/test_cenum.h +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/link/c/c_code/test_quadratic_function.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/tensor/conv/c_code/corr3d_gemm.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/tensor/conv/c_code/corr_gemm.c +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_breakpoint.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_config.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_gradient.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_ifelse.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_printing.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_raise_op.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_rop.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/tests/test_updates.py +0 -0
- {pytensor-2.17.4 → pytensor-2.18.0}/versioneer.py +0 -0
|
@@ -82,9 +82,6 @@ PyTensor can produce :class:`RandomVariable`\s that draw samples from many diffe
|
|
|
82
82
|
.. autoclass:: pytensor.tensor.random.basic.CategoricalRV
|
|
83
83
|
:members: __call__
|
|
84
84
|
|
|
85
|
-
.. autoclass:: pytensor.tensor.random.basic.ChiSquareRV
|
|
86
|
-
:members: __call__
|
|
87
|
-
|
|
88
85
|
.. autoclass:: pytensor.tensor.random.basic.DirichletRV
|
|
89
86
|
:members: __call__
|
|
90
87
|
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-11-
|
|
11
|
+
"date": "2023-11-20T14:04:50+0100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.
|
|
14
|
+
"full-revisionid": "eb552eef7a8381e47a38ce0694244700693cb978",
|
|
15
|
+
"version": "2.18.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -101,7 +101,7 @@ def grad_undefined(op, x_pos, x, comment=""):
|
|
|
101
101
|
return (
|
|
102
102
|
NullType(
|
|
103
103
|
"This variable is Null because the grad method for "
|
|
104
|
-
f"input {x_pos} ({x}) of the {op} op is
|
|
104
|
+
f"input {x_pos} ({x}) of the {op} op is undefined. {comment}"
|
|
105
105
|
)
|
|
106
106
|
)()
|
|
107
107
|
|
|
@@ -9,7 +9,7 @@ from pytensor.graph.basic import (
|
|
|
9
9
|
clone,
|
|
10
10
|
ancestors,
|
|
11
11
|
)
|
|
12
|
-
from pytensor.graph.replace import clone_replace, graph_replace,
|
|
12
|
+
from pytensor.graph.replace import clone_replace, graph_replace, vectorize_graph
|
|
13
13
|
from pytensor.graph.op import Op
|
|
14
14
|
from pytensor.graph.type import Type
|
|
15
15
|
from pytensor.graph.fg import FunctionGraph
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import warnings
|
|
1
2
|
from collections.abc import Iterable, Mapping, Sequence
|
|
2
3
|
from functools import partial, singledispatch
|
|
3
4
|
from typing import Optional, Union, cast, overload
|
|
@@ -203,7 +204,7 @@ def graph_replace(
|
|
|
203
204
|
|
|
204
205
|
|
|
205
206
|
@singledispatch
|
|
206
|
-
def _vectorize_node(op: Op, node: Apply, *
|
|
207
|
+
def _vectorize_node(op: Op, node: Apply, *batched_inputs) -> Apply:
|
|
207
208
|
# Default implementation is provided in pytensor.tensor.blockwise
|
|
208
209
|
raise NotImplementedError
|
|
209
210
|
|
|
@@ -214,8 +215,12 @@ def vectorize_node(node: Apply, *batched_inputs) -> Apply:
|
|
|
214
215
|
return _vectorize_node(op, node, *batched_inputs)
|
|
215
216
|
|
|
216
217
|
|
|
218
|
+
def _vectorize_not_needed(op, node, *batched_inputs):
|
|
219
|
+
return op.make_node(*batched_inputs)
|
|
220
|
+
|
|
221
|
+
|
|
217
222
|
@overload
|
|
218
|
-
def
|
|
223
|
+
def vectorize_graph(
|
|
219
224
|
outputs: Variable,
|
|
220
225
|
replace: Mapping[Variable, Variable],
|
|
221
226
|
) -> Variable:
|
|
@@ -223,14 +228,14 @@ def vectorize(
|
|
|
223
228
|
|
|
224
229
|
|
|
225
230
|
@overload
|
|
226
|
-
def
|
|
231
|
+
def vectorize_graph(
|
|
227
232
|
outputs: Sequence[Variable],
|
|
228
233
|
replace: Mapping[Variable, Variable],
|
|
229
234
|
) -> Sequence[Variable]:
|
|
230
235
|
...
|
|
231
236
|
|
|
232
237
|
|
|
233
|
-
def
|
|
238
|
+
def vectorize_graph(
|
|
234
239
|
outputs: Union[Variable, Sequence[Variable]],
|
|
235
240
|
replace: Mapping[Variable, Variable],
|
|
236
241
|
) -> Union[Variable, Sequence[Variable]]:
|
|
@@ -309,3 +314,8 @@ def vectorize(
|
|
|
309
314
|
else:
|
|
310
315
|
[vect_output] = seq_vect_outputs
|
|
311
316
|
return vect_output
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def vectorize(*args, **kwargs):
|
|
320
|
+
warnings.warn("vectorize was renamed to vectorize_graph", UserWarning)
|
|
321
|
+
return vectorize_graph(*args, **kwargs)
|
|
@@ -2731,6 +2731,15 @@ def default_blas_ldflags():
|
|
|
2731
2731
|
shell=True,
|
|
2732
2732
|
)
|
|
2733
2733
|
(stdout, stderr) = p.communicate(input=b"")
|
|
2734
|
+
if p.returncode != 0:
|
|
2735
|
+
warnings.warn(
|
|
2736
|
+
"Pytensor cxx failed to communicate its search dirs. As a consequence, "
|
|
2737
|
+
"it might not be possible to automatically determine the blas link flags to use.\n"
|
|
2738
|
+
f"Command that was run: {config.cxx} -print-search-dirs\n"
|
|
2739
|
+
f"Output printed to stderr: {stderr.decode(sys.stderr.encoding)}"
|
|
2740
|
+
)
|
|
2741
|
+
return []
|
|
2742
|
+
|
|
2734
2743
|
maybe_lib_dirs = [
|
|
2735
2744
|
[pathlib.Path(p).resolve() for p in line[len("libraries: =") :].split(":")]
|
|
2736
2745
|
for line in stdout.decode(sys.stdout.encoding).splitlines()
|
|
@@ -2773,6 +2782,9 @@ def default_blas_ldflags():
|
|
|
2773
2782
|
else:
|
|
2774
2783
|
raise RuntimeError(f"Supplied flags {flags} failed to compile")
|
|
2775
2784
|
|
|
2785
|
+
# If no compiler is available we default to empty ldflags
|
|
2786
|
+
if not config.cxx:
|
|
2787
|
+
return ""
|
|
2776
2788
|
_std_lib_dirs = std_lib_dirs()
|
|
2777
2789
|
if len(_std_lib_dirs) > 0:
|
|
2778
2790
|
rpath = _std_lib_dirs[0]
|
|
@@ -20,7 +20,17 @@ from pytensor.scalar.basic import (
|
|
|
20
20
|
Second,
|
|
21
21
|
Sub,
|
|
22
22
|
)
|
|
23
|
-
from pytensor.scalar.math import
|
|
23
|
+
from pytensor.scalar.math import (
|
|
24
|
+
Erf,
|
|
25
|
+
Erfc,
|
|
26
|
+
Erfcinv,
|
|
27
|
+
Erfcx,
|
|
28
|
+
Erfinv,
|
|
29
|
+
Iv,
|
|
30
|
+
Log1mexp,
|
|
31
|
+
Psi,
|
|
32
|
+
TriGamma,
|
|
33
|
+
)
|
|
24
34
|
|
|
25
35
|
|
|
26
36
|
def try_import_tfp_jax_op(op: ScalarOp, jax_op_name: Optional[str] = None) -> Callable:
|
|
@@ -37,7 +47,7 @@ def try_import_tfp_jax_op(op: ScalarOp, jax_op_name: Optional[str] = None) -> Ca
|
|
|
37
47
|
return typing.cast(Callable, getattr(tfp_jax_math, jax_op_name))
|
|
38
48
|
|
|
39
49
|
|
|
40
|
-
def
|
|
50
|
+
def all_inputs_are_scalar(node):
|
|
41
51
|
"""Check whether all the inputs of an `Elemwise` are scalar values.
|
|
42
52
|
|
|
43
53
|
`jax.lax` or `jax.numpy` functions systematically return `TracedArrays`,
|
|
@@ -62,56 +72,68 @@ def check_if_inputs_scalars(node):
|
|
|
62
72
|
|
|
63
73
|
@jax_funcify.register(ScalarOp)
|
|
64
74
|
def jax_funcify_ScalarOp(op, node, **kwargs):
|
|
65
|
-
|
|
75
|
+
"""Return JAX function that implements the same computation as the Scalar Op.
|
|
76
|
+
|
|
77
|
+
This dispatch is expected to return a JAX function that works on Array inputs as Elemwise does,
|
|
78
|
+
even though it's dispatched on the Scalar Op.
|
|
79
|
+
"""
|
|
66
80
|
|
|
67
81
|
# We dispatch some PyTensor operators to Python operators
|
|
68
82
|
# whenever the inputs are all scalars.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
if all_inputs_are_scalar(node):
|
|
84
|
+
jax_func = jax_funcify_scalar_op_via_py_operators(op)
|
|
85
|
+
if jax_func is not None:
|
|
86
|
+
return jax_func
|
|
87
|
+
|
|
88
|
+
nfunc_spec = getattr(op, "nfunc_spec", None)
|
|
89
|
+
if nfunc_spec is None:
|
|
90
|
+
raise NotImplementedError(f"Dispatch not implemented for Scalar Op {op}")
|
|
74
91
|
|
|
92
|
+
func_name = nfunc_spec[0]
|
|
75
93
|
if "." in func_name:
|
|
76
|
-
|
|
94
|
+
jax_func = functools.reduce(getattr, [jax] + func_name.split("."))
|
|
77
95
|
else:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
else:
|
|
97
|
-
return jnp_func
|
|
96
|
+
jax_func = getattr(jnp, func_name)
|
|
97
|
+
|
|
98
|
+
if len(node.inputs) > op.nfunc_spec[1]:
|
|
99
|
+
# Some Scalar Ops accept multiple number of inputs, behaving as a variadic function,
|
|
100
|
+
# even though the base Op from `func_name` is specified as a binary Op.
|
|
101
|
+
# This happens with `Add`, which can work as a `Sum` for multiple scalars.
|
|
102
|
+
jax_variadic_func = getattr(jnp, op.nfunc_variadic, None)
|
|
103
|
+
if not jax_variadic_func:
|
|
104
|
+
raise NotImplementedError(
|
|
105
|
+
f"Dispatch not implemented for Scalar Op {op} with {len(node.inputs)} inputs"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def jax_func(*args):
|
|
109
|
+
return jax_variadic_func(
|
|
110
|
+
jnp.stack(jnp.broadcast_arrays(*args), axis=0), axis=0
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
return jax_func
|
|
98
114
|
|
|
99
115
|
|
|
100
116
|
@functools.singledispatch
|
|
101
|
-
def
|
|
117
|
+
def jax_funcify_scalar_op_via_py_operators(op):
|
|
118
|
+
"""Specialized JAX dispatch for Elemwise operations where all inputs are Scalar arrays.
|
|
119
|
+
|
|
120
|
+
Scalar (constant) arrays in the JAX backend get lowered to the native types (int, floats),
|
|
121
|
+
which can perform better with Python operators, and more importantly, avoid upcasting to array types
|
|
122
|
+
not supported by some JAX functions.
|
|
123
|
+
"""
|
|
102
124
|
return None
|
|
103
125
|
|
|
104
126
|
|
|
105
|
-
@
|
|
106
|
-
def
|
|
127
|
+
@jax_funcify_scalar_op_via_py_operators.register(Add)
|
|
128
|
+
def jax_funcify_scalar_Add(op):
|
|
107
129
|
def elemwise(*inputs):
|
|
108
130
|
return sum(inputs)
|
|
109
131
|
|
|
110
132
|
return elemwise
|
|
111
133
|
|
|
112
134
|
|
|
113
|
-
@
|
|
114
|
-
def
|
|
135
|
+
@jax_funcify_scalar_op_via_py_operators.register(Mul)
|
|
136
|
+
def jax_funcify_scalar_Mul(op):
|
|
115
137
|
import operator
|
|
116
138
|
from functools import reduce
|
|
117
139
|
|
|
@@ -121,24 +143,24 @@ def elemwise_scalar_mul(op):
|
|
|
121
143
|
return elemwise
|
|
122
144
|
|
|
123
145
|
|
|
124
|
-
@
|
|
125
|
-
def
|
|
146
|
+
@jax_funcify_scalar_op_via_py_operators.register(Sub)
|
|
147
|
+
def jax_funcify_scalar_Sub(op):
|
|
126
148
|
def elemwise(x, y):
|
|
127
149
|
return x - y
|
|
128
150
|
|
|
129
151
|
return elemwise
|
|
130
152
|
|
|
131
153
|
|
|
132
|
-
@
|
|
133
|
-
def
|
|
154
|
+
@jax_funcify_scalar_op_via_py_operators.register(IntDiv)
|
|
155
|
+
def jax_funcify_scalar_IntDiv(op):
|
|
134
156
|
def elemwise(x, y):
|
|
135
157
|
return x // y
|
|
136
158
|
|
|
137
159
|
return elemwise
|
|
138
160
|
|
|
139
161
|
|
|
140
|
-
@
|
|
141
|
-
def
|
|
162
|
+
@jax_funcify_scalar_op_via_py_operators.register(Mod)
|
|
163
|
+
def jax_funcify_scalar_Mod(op):
|
|
142
164
|
def elemwise(x, y):
|
|
143
165
|
return x % y
|
|
144
166
|
|
|
@@ -263,6 +285,14 @@ def jax_funcify_Psi(op, node, **kwargs):
|
|
|
263
285
|
return psi
|
|
264
286
|
|
|
265
287
|
|
|
288
|
+
@jax_funcify.register(TriGamma)
|
|
289
|
+
def jax_funcify_TriGamma(op, node, **kwargs):
|
|
290
|
+
def tri_gamma(x):
|
|
291
|
+
return jax.scipy.special.polygamma(1, x)
|
|
292
|
+
|
|
293
|
+
return tri_gamma
|
|
294
|
+
|
|
295
|
+
|
|
266
296
|
@jax_funcify.register(Softplus)
|
|
267
297
|
def jax_funcify_Softplus(op, **kwargs):
|
|
268
298
|
def softplus(x):
|
|
@@ -195,7 +195,6 @@ def {sized_fn_name}({random_fn_input_names}):
|
|
|
195
195
|
@numba_funcify.register(aer.NormalRV)
|
|
196
196
|
@numba_funcify.register(aer.LogNormalRV)
|
|
197
197
|
@numba_funcify.register(aer.GammaRV)
|
|
198
|
-
@numba_funcify.register(aer.ChiSquareRV)
|
|
199
198
|
@numba_funcify.register(aer.ParetoRV)
|
|
200
199
|
@numba_funcify.register(aer.GumbelRV)
|
|
201
200
|
@numba_funcify.register(aer.ExponentialRV)
|
|
@@ -13,7 +13,7 @@ import scipy.special
|
|
|
13
13
|
import scipy.stats
|
|
14
14
|
|
|
15
15
|
from pytensor.configdefaults import config
|
|
16
|
-
from pytensor.gradient import grad_not_implemented
|
|
16
|
+
from pytensor.gradient import grad_not_implemented, grad_undefined
|
|
17
17
|
from pytensor.scalar.basic import BinaryScalarOp, ScalarOp, UnaryScalarOp
|
|
18
18
|
from pytensor.scalar.basic import abs as scalar_abs
|
|
19
19
|
from pytensor.scalar.basic import (
|
|
@@ -473,8 +473,12 @@ class TriGamma(UnaryScalarOp):
|
|
|
473
473
|
def impl(self, x):
|
|
474
474
|
return TriGamma.st_impl(x)
|
|
475
475
|
|
|
476
|
-
def
|
|
477
|
-
|
|
476
|
+
def L_op(self, inputs, outputs, outputs_gradients):
|
|
477
|
+
(x,) = inputs
|
|
478
|
+
(g_out,) = outputs_gradients
|
|
479
|
+
if x in complex_types:
|
|
480
|
+
raise NotImplementedError("gradient not implemented for complex types")
|
|
481
|
+
return [g_out * polygamma(2, x)]
|
|
478
482
|
|
|
479
483
|
def c_support_code(self, **kwargs):
|
|
480
484
|
# The implementation has been copied from
|
|
@@ -541,7 +545,52 @@ class TriGamma(UnaryScalarOp):
|
|
|
541
545
|
raise NotImplementedError("only floating point is implemented")
|
|
542
546
|
|
|
543
547
|
|
|
544
|
-
|
|
548
|
+
# Scipy polygamma does not support complex inputs: https://github.com/scipy/scipy/issues/7410
|
|
549
|
+
tri_gamma = TriGamma(upgrade_to_float_no_complex, name="tri_gamma")
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
class PolyGamma(BinaryScalarOp):
|
|
553
|
+
"""Polygamma function of order n evaluated at x.
|
|
554
|
+
|
|
555
|
+
It corresponds to the (n+1)th derivative of the log gamma function.
|
|
556
|
+
|
|
557
|
+
TODO: Because the first input is discrete and the output is continuous,
|
|
558
|
+
the default elemwise inplace won't work, as it always tries to store the results in the first input.
|
|
559
|
+
"""
|
|
560
|
+
|
|
561
|
+
nfunc_spec = ("scipy.special.polygamma", 2, 1)
|
|
562
|
+
|
|
563
|
+
@staticmethod
|
|
564
|
+
def output_types_preference(n_type, x_type):
|
|
565
|
+
if n_type not in discrete_types:
|
|
566
|
+
raise TypeError(
|
|
567
|
+
f"Polygamma order parameter must be discrete, got {n_type} dtype"
|
|
568
|
+
)
|
|
569
|
+
# Scipy doesn't support it
|
|
570
|
+
return upgrade_to_float_no_complex(x_type)
|
|
571
|
+
|
|
572
|
+
@staticmethod
|
|
573
|
+
def st_impl(n, x):
|
|
574
|
+
return scipy.special.polygamma(n, x)
|
|
575
|
+
|
|
576
|
+
def impl(self, n, x):
|
|
577
|
+
return PolyGamma.st_impl(n, x)
|
|
578
|
+
|
|
579
|
+
def L_op(self, inputs, outputs, output_gradients):
|
|
580
|
+
(n, x) = inputs
|
|
581
|
+
(g_out,) = output_gradients
|
|
582
|
+
if x in complex_types:
|
|
583
|
+
raise NotImplementedError("gradient not implemented for complex types")
|
|
584
|
+
return [
|
|
585
|
+
grad_undefined(self, 0, n),
|
|
586
|
+
g_out * self(n + 1, x),
|
|
587
|
+
]
|
|
588
|
+
|
|
589
|
+
def c_code(self, *args, **kwargs):
|
|
590
|
+
raise NotImplementedError()
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
polygamma = PolyGamma(name="polygamma")
|
|
545
594
|
|
|
546
595
|
|
|
547
596
|
class Chi2SF(BinaryScalarOp):
|
|
@@ -148,6 +148,7 @@ from pytensor.tensor.subtensor import * # noqa
|
|
|
148
148
|
from pytensor.tensor.type import * # noqa
|
|
149
149
|
from pytensor.tensor.type_other import * # noqa
|
|
150
150
|
from pytensor.tensor.variable import TensorConstant, TensorVariable # noqa
|
|
151
|
+
from pytensor.tensor.functional import vectorize # noqa
|
|
151
152
|
|
|
152
153
|
# Allow accessing numpy constants from pytensor.tensor
|
|
153
154
|
from numpy import e, euler_gamma, inf, infty, nan, newaxis, pi # noqa
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import re
|
|
2
1
|
from collections.abc import Sequence
|
|
3
2
|
from typing import Any, Optional, cast
|
|
4
3
|
|
|
@@ -9,53 +8,22 @@ from pytensor.gradient import DisconnectedType
|
|
|
9
8
|
from pytensor.graph.basic import Apply, Constant, Variable
|
|
10
9
|
from pytensor.graph.null_type import NullType
|
|
11
10
|
from pytensor.graph.op import Op
|
|
12
|
-
from pytensor.graph.replace import
|
|
11
|
+
from pytensor.graph.replace import (
|
|
12
|
+
_vectorize_node,
|
|
13
|
+
_vectorize_not_needed,
|
|
14
|
+
vectorize_graph,
|
|
15
|
+
)
|
|
13
16
|
from pytensor.tensor import as_tensor_variable
|
|
14
17
|
from pytensor.tensor.shape import shape_padleft
|
|
15
18
|
from pytensor.tensor.type import continuous_dtypes, discrete_dtypes, tensor
|
|
16
|
-
from pytensor.tensor.utils import
|
|
19
|
+
from pytensor.tensor.utils import (
|
|
20
|
+
_parse_gufunc_signature,
|
|
21
|
+
broadcast_static_dim_lengths,
|
|
22
|
+
import_func_from_string,
|
|
23
|
+
)
|
|
17
24
|
from pytensor.tensor.variable import TensorVariable
|
|
18
25
|
|
|
19
26
|
|
|
20
|
-
# TODO: Implement vectorize helper to batch whole graphs (similar to what Blockwise does for the grad)
|
|
21
|
-
|
|
22
|
-
# Copied verbatim from numpy.lib.function_base
|
|
23
|
-
# https://github.com/numpy/numpy/blob/f2db090eb95b87d48a3318c9a3f9d38b67b0543c/numpy/lib/function_base.py#L1999-L2029
|
|
24
|
-
_DIMENSION_NAME = r"\w+"
|
|
25
|
-
_CORE_DIMENSION_LIST = "(?:{0:}(?:,{0:})*)?".format(_DIMENSION_NAME)
|
|
26
|
-
_ARGUMENT = rf"\({_CORE_DIMENSION_LIST}\)"
|
|
27
|
-
_ARGUMENT_LIST = "{0:}(?:,{0:})*".format(_ARGUMENT)
|
|
28
|
-
_SIGNATURE = "^{0:}->{0:}$".format(_ARGUMENT_LIST)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _parse_gufunc_signature(signature):
|
|
32
|
-
"""
|
|
33
|
-
Parse string signatures for a generalized universal function.
|
|
34
|
-
|
|
35
|
-
Arguments
|
|
36
|
-
---------
|
|
37
|
-
signature : string
|
|
38
|
-
Generalized universal function signature, e.g., ``(m,n),(n,p)->(m,p)``
|
|
39
|
-
for ``np.matmul``.
|
|
40
|
-
|
|
41
|
-
Returns
|
|
42
|
-
-------
|
|
43
|
-
Tuple of input and output core dimensions parsed from the signature, each
|
|
44
|
-
of the form List[Tuple[str, ...]].
|
|
45
|
-
"""
|
|
46
|
-
signature = re.sub(r"\s+", "", signature)
|
|
47
|
-
|
|
48
|
-
if not re.match(_SIGNATURE, signature):
|
|
49
|
-
raise ValueError(f"not a valid gufunc signature: {signature}")
|
|
50
|
-
return tuple(
|
|
51
|
-
[
|
|
52
|
-
tuple(re.findall(_DIMENSION_NAME, arg))
|
|
53
|
-
for arg in re.findall(_ARGUMENT, arg_list)
|
|
54
|
-
]
|
|
55
|
-
for arg_list in signature.split("->")
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
27
|
def safe_signature(
|
|
60
28
|
core_inputs: Sequence[Variable],
|
|
61
29
|
core_outputs: Sequence[Variable],
|
|
@@ -73,17 +41,6 @@ def safe_signature(
|
|
|
73
41
|
return f"{inputs_sig}->{outputs_sig}"
|
|
74
42
|
|
|
75
43
|
|
|
76
|
-
@_vectorize_node.register(Op)
|
|
77
|
-
def vectorize_node_fallback(op: Op, node: Apply, *bached_inputs) -> Apply:
|
|
78
|
-
if hasattr(op, "gufunc_signature"):
|
|
79
|
-
signature = op.gufunc_signature
|
|
80
|
-
else:
|
|
81
|
-
# TODO: This is pretty bad for shape inference and merge optimization!
|
|
82
|
-
# Should get better as we add signatures to our Ops
|
|
83
|
-
signature = safe_signature(node.inputs, node.outputs)
|
|
84
|
-
return cast(Apply, Blockwise(op, signature=signature).make_node(*bached_inputs))
|
|
85
|
-
|
|
86
|
-
|
|
87
44
|
class Blockwise(Op):
|
|
88
45
|
"""Generalizes a core `Op` to work with batched dimensions.
|
|
89
46
|
|
|
@@ -274,7 +231,7 @@ class Blockwise(Op):
|
|
|
274
231
|
|
|
275
232
|
core_igrads = self.core_op.L_op(core_inputs, core_outputs, core_ograds)
|
|
276
233
|
|
|
277
|
-
igrads =
|
|
234
|
+
igrads = vectorize_graph(
|
|
278
235
|
[core_igrad for core_igrad in core_igrads if core_igrad is not None],
|
|
279
236
|
replace=dict(
|
|
280
237
|
zip(core_inputs + core_outputs + core_ograds, inputs + outputs + ograds)
|
|
@@ -397,6 +354,15 @@ class Blockwise(Op):
|
|
|
397
354
|
return self.name
|
|
398
355
|
|
|
399
356
|
|
|
400
|
-
@_vectorize_node.register(
|
|
401
|
-
def
|
|
402
|
-
|
|
357
|
+
@_vectorize_node.register(Op)
|
|
358
|
+
def vectorize_node_fallback(op: Op, node: Apply, *bached_inputs) -> Apply:
|
|
359
|
+
if hasattr(op, "gufunc_signature"):
|
|
360
|
+
signature = op.gufunc_signature
|
|
361
|
+
else:
|
|
362
|
+
# TODO: This is pretty bad for shape inference and merge optimization!
|
|
363
|
+
# Should get better as we add signatures to our Ops
|
|
364
|
+
signature = safe_signature(node.inputs, node.outputs)
|
|
365
|
+
return cast(Apply, Blockwise(op, signature=signature).make_node(*bached_inputs))
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
_vectorize_node.register(Blockwise, _vectorize_not_needed)
|
|
@@ -7,7 +7,7 @@ from pytensor.configdefaults import config
|
|
|
7
7
|
from pytensor.gradient import DisconnectedType
|
|
8
8
|
from pytensor.graph.basic import Apply
|
|
9
9
|
from pytensor.graph.null_type import NullType
|
|
10
|
-
from pytensor.graph.replace import _vectorize_node
|
|
10
|
+
from pytensor.graph.replace import _vectorize_node, _vectorize_not_needed
|
|
11
11
|
from pytensor.graph.utils import MethodNotDefined
|
|
12
12
|
from pytensor.link.c.basic import failure_code
|
|
13
13
|
from pytensor.link.c.op import COp, ExternalCOp, OpenMPOp
|
|
@@ -22,7 +22,6 @@ from pytensor.scalar.basic import transfer_type, upcast
|
|
|
22
22
|
from pytensor.tensor import elemwise_cgen as cgen
|
|
23
23
|
from pytensor.tensor import get_vector_length
|
|
24
24
|
from pytensor.tensor.basic import _get_vector_length, as_tensor_variable
|
|
25
|
-
from pytensor.tensor.blockwise import vectorize_not_needed
|
|
26
25
|
from pytensor.tensor.type import (
|
|
27
26
|
TensorType,
|
|
28
27
|
continuous_dtypes,
|
|
@@ -1741,7 +1740,7 @@ def _get_vector_length_Elemwise(op, var):
|
|
|
1741
1740
|
raise ValueError(f"Length of {var} cannot be determined")
|
|
1742
1741
|
|
|
1743
1742
|
|
|
1744
|
-
_vectorize_node.register(Elemwise,
|
|
1743
|
+
_vectorize_node.register(Elemwise, _vectorize_not_needed)
|
|
1745
1744
|
|
|
1746
1745
|
|
|
1747
1746
|
@_vectorize_node.register(DimShuffle)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from typing import Callable, Optional
|
|
2
|
+
|
|
3
|
+
from pytensor.graph import vectorize_graph
|
|
4
|
+
from pytensor.tensor import TensorVariable
|
|
5
|
+
from pytensor.tensor.utils import _parse_gufunc_signature
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def vectorize(func: Callable, signature: Optional[str] = None) -> Callable:
|
|
9
|
+
"""Create a vectorized version of a python function that takes TensorVariables as inputs and outputs.
|
|
10
|
+
|
|
11
|
+
Similar to numpy.vectorize. See respective docstrings for more details.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
func: Callable
|
|
16
|
+
Function that creates the desired outputs from TensorVariable inputs with the core dimensions.
|
|
17
|
+
signature: str, optional
|
|
18
|
+
Generalized universal function signature, e.g., (m,n),(n)->(m) for vectorized matrix-vector multiplication.
|
|
19
|
+
If not provided, it is assumed all inputs have scalar core dimensions. Unlike numpy, the outputs
|
|
20
|
+
can have arbitrary shapes when the signature is not provided.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
vectorized_func: Callable
|
|
25
|
+
Callable that takes TensorVariables with arbitrarily batched dimensions on the left
|
|
26
|
+
and returns variables whose graphs correspond to the vectorized expressions of func.
|
|
27
|
+
|
|
28
|
+
Notes
|
|
29
|
+
-----
|
|
30
|
+
Unlike numpy.vectorize, the equality of core dimensions implied by the signature is not explicitly asserted.
|
|
31
|
+
|
|
32
|
+
To vectorize an existing graph, use `pytensor.graph.replace.vectorize_graph` instead.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
Examples
|
|
36
|
+
--------
|
|
37
|
+
.. code-block:: python
|
|
38
|
+
|
|
39
|
+
import pytensor
|
|
40
|
+
import pytensor.tensor as pt
|
|
41
|
+
|
|
42
|
+
def func(x):
|
|
43
|
+
return pt.exp(x) / pt.sum(pt.exp(x))
|
|
44
|
+
|
|
45
|
+
vec_func = pt.vectorize(func, signature="(a)->(a)")
|
|
46
|
+
|
|
47
|
+
x = pt.matrix("x")
|
|
48
|
+
y = vec_func(x)
|
|
49
|
+
|
|
50
|
+
fn = pytensor.function([x], y)
|
|
51
|
+
fn([[0, 1, 2], [2, 1, 0]])
|
|
52
|
+
# array([[0.09003057, 0.24472847, 0.66524096],
|
|
53
|
+
# [0.66524096, 0.24472847, 0.09003057]])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
.. code-block:: python
|
|
57
|
+
|
|
58
|
+
import pytensor
|
|
59
|
+
import pytensor.tensor as pt
|
|
60
|
+
|
|
61
|
+
def func(x):
|
|
62
|
+
return x[0], x[-1]
|
|
63
|
+
|
|
64
|
+
vec_func = pt.vectorize(func, signature="(a)->(),()")
|
|
65
|
+
|
|
66
|
+
x = pt.matrix("x")
|
|
67
|
+
y1, y2 = vec_func(x)
|
|
68
|
+
|
|
69
|
+
fn = pytensor.function([x], [y1, y2])
|
|
70
|
+
fn([[-10, 0, 10], [-11, 0, 11]])
|
|
71
|
+
# [array([-10., -11.]), array([10., 11.])]
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def inner(*inputs):
|
|
76
|
+
if signature is None:
|
|
77
|
+
# Assume all inputs are scalar
|
|
78
|
+
inputs_sig = [()] * len(inputs)
|
|
79
|
+
else:
|
|
80
|
+
inputs_sig, outputs_sig = _parse_gufunc_signature(signature)
|
|
81
|
+
if len(inputs) != len(inputs_sig):
|
|
82
|
+
raise ValueError(
|
|
83
|
+
f"Number of inputs does not match signature: {signature}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Create dummy core inputs by stripping the batched dimensions of inputs
|
|
87
|
+
core_inputs = []
|
|
88
|
+
for input, input_sig in zip(inputs, inputs_sig):
|
|
89
|
+
if not isinstance(input, TensorVariable):
|
|
90
|
+
raise TypeError(
|
|
91
|
+
f"Inputs to vectorize function must be TensorVariable, got {type(input)}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if input.ndim < len(input_sig):
|
|
95
|
+
raise ValueError(
|
|
96
|
+
f"Input {input} has less dimensions than signature {input_sig}"
|
|
97
|
+
)
|
|
98
|
+
if len(input_sig):
|
|
99
|
+
core_shape = input.type.shape[-len(input_sig) :]
|
|
100
|
+
else:
|
|
101
|
+
core_shape = ()
|
|
102
|
+
|
|
103
|
+
core_input = input.type.clone(shape=core_shape)(name=input.name)
|
|
104
|
+
core_inputs.append(core_input)
|
|
105
|
+
|
|
106
|
+
# Call function on dummy core inputs
|
|
107
|
+
core_outputs = func(*core_inputs)
|
|
108
|
+
if core_outputs is None:
|
|
109
|
+
raise ValueError("vectorize function returned no outputs")
|
|
110
|
+
|
|
111
|
+
if signature is not None:
|
|
112
|
+
if isinstance(core_outputs, (list, tuple)):
|
|
113
|
+
n_core_outputs = len(core_outputs)
|
|
114
|
+
else:
|
|
115
|
+
n_core_outputs = 1
|
|
116
|
+
if n_core_outputs != len(outputs_sig):
|
|
117
|
+
raise ValueError(
|
|
118
|
+
f"Number of outputs does not match signature: {signature}"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Vectorize graph by replacing dummy core inputs by original inputs
|
|
122
|
+
outputs = vectorize_graph(core_outputs, replace=dict(zip(core_inputs, inputs)))
|
|
123
|
+
return outputs
|
|
124
|
+
|
|
125
|
+
return inner
|