pytensor 2.24.0__tar.gz → 2.24.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.
Files changed (417) hide show
  1. {pytensor-2.24.0 → pytensor-2.24.1}/PKG-INFO +1 -1
  2. {pytensor-2.24.0 → pytensor-2.24.1}/doc/conf.py +8 -0
  3. {pytensor-2.24.0 → pytensor-2.24.1}/doc/environment.yml +1 -0
  4. pytensor-2.24.1/doc/extending/creating_a_numba_jax_op.rst +653 -0
  5. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/_version.py +3 -3
  6. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/pytorch/dispatch/__init__.py +1 -0
  7. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/pytorch/dispatch/basic.py +12 -1
  8. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/pytorch/dispatch/elemwise.py +64 -0
  9. pytensor-2.24.1/pytensor/link/pytorch/dispatch/extra_ops.py +23 -0
  10. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/extra_ops.py +2 -0
  11. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/subtensor.py +1 -1
  12. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/PKG-INFO +1 -1
  13. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/SOURCES.txt +1 -0
  14. pytensor-2.24.0/doc/extending/creating_a_numba_jax_op.rst +0 -285
  15. {pytensor-2.24.0 → pytensor-2.24.1}/LICENSE.txt +0 -0
  16. {pytensor-2.24.0 → pytensor-2.24.1}/MANIFEST.in +0 -0
  17. {pytensor-2.24.0 → pytensor-2.24.1}/README.rst +0 -0
  18. {pytensor-2.24.0 → pytensor-2.24.1}/doc/.templates/PLACEHOLDER +0 -0
  19. {pytensor-2.24.0 → pytensor-2.24.1}/doc/.templates/layout.html +0 -0
  20. {pytensor-2.24.0 → pytensor-2.24.1}/doc/LICENSE.txt +0 -0
  21. {pytensor-2.24.0 → pytensor-2.24.1}/doc/README.md +0 -0
  22. {pytensor-2.24.0 → pytensor-2.24.1}/doc/acknowledgement.rst +0 -0
  23. {pytensor-2.24.0 → pytensor-2.24.1}/doc/bcast.png +0 -0
  24. {pytensor-2.24.0 → pytensor-2.24.1}/doc/bcast.svg +0 -0
  25. {pytensor-2.24.0 → pytensor-2.24.1}/doc/core_development_guide.rst +0 -0
  26. {pytensor-2.24.0 → pytensor-2.24.1}/doc/css.inc +0 -0
  27. {pytensor-2.24.0 → pytensor-2.24.1}/doc/dev_start_guide.rst +0 -0
  28. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/apply.png +0 -0
  29. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/apply.svg +0 -0
  30. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/apply2.svg +0 -0
  31. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/creating_a_c_op.rst +0 -0
  32. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/creating_an_op.rst +0 -0
  33. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/ctype.rst +0 -0
  34. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/extending_faq.rst +0 -0
  35. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/extending_pytensor_solution_1.py +0 -0
  36. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/graph_rewriting.rst +0 -0
  37. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/graphstructures.rst +0 -0
  38. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/index.rst +0 -0
  39. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/inplace.rst +0 -0
  40. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/op.rst +0 -0
  41. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/other_ops.rst +0 -0
  42. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/pics/symbolic_graph_opt.png +0 -0
  43. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/pics/symbolic_graph_unopt.png +0 -0
  44. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/pipeline.rst +0 -0
  45. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/scan.rst +0 -0
  46. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/tips.rst +0 -0
  47. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/type.rst +0 -0
  48. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/unittest.rst +0 -0
  49. {pytensor-2.24.0 → pytensor-2.24.1}/doc/extending/using_params.rst +0 -0
  50. {pytensor-2.24.0 → pytensor-2.24.1}/doc/faq.rst +0 -0
  51. {pytensor-2.24.0 → pytensor-2.24.1}/doc/generate_dtype_tensor_table.py +0 -0
  52. {pytensor-2.24.0 → pytensor-2.24.1}/doc/glossary.rst +0 -0
  53. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/Elman_srnn.png +0 -0
  54. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/PyTensor_RGB.svg +0 -0
  55. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/blocksparse.png +0 -0
  56. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/lstm.png +0 -0
  57. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/lstm_memorycell.png +0 -0
  58. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/talk2010.gif +0 -0
  59. {pytensor-2.24.0 → pytensor-2.24.1}/doc/images/talk2010.png +0 -0
  60. {pytensor-2.24.0 → pytensor-2.24.1}/doc/index.rst +0 -0
  61. {pytensor-2.24.0 → pytensor-2.24.1}/doc/install.rst +0 -0
  62. {pytensor-2.24.0 → pytensor-2.24.1}/doc/internal/how_to_release.rst +0 -0
  63. {pytensor-2.24.0 → pytensor-2.24.1}/doc/internal/index.rst +0 -0
  64. {pytensor-2.24.0 → pytensor-2.24.1}/doc/internal/metadocumentation.rst +0 -0
  65. {pytensor-2.24.0 → pytensor-2.24.1}/doc/introduction.rst +0 -0
  66. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/debugmode.rst +0 -0
  67. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/function.rst +0 -0
  68. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/index.rst +0 -0
  69. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/io.rst +0 -0
  70. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/mode.rst +0 -0
  71. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/nanguardmode.rst +0 -0
  72. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/opfromgraph.rst +0 -0
  73. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/ops.rst +0 -0
  74. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/profilemode.rst +0 -0
  75. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/compile/shared.rst +0 -0
  76. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/config.rst +0 -0
  77. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/css/d3-context-menu.css +0 -0
  78. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/css/d3viz.css +0 -0
  79. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/js/d3-context-menu.js +0 -0
  80. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/js/d3.v3.min.js +0 -0
  81. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/js/d3viz.js +0 -0
  82. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/js/dagre-d3.min.js +0 -0
  83. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/d3viz/js/graphlib-dot.min.js +0 -0
  84. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/mlp.html +0 -0
  85. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/mlp.png +0 -0
  86. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/mlp2.html +0 -0
  87. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/mlp2.pdf +0 -0
  88. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/mlp2.png +0 -0
  89. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/ofg.html +0 -0
  90. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/examples/ofg2.html +0 -0
  91. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index.ipynb +0 -0
  92. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index.rst +0 -0
  93. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index_files/index_10_0.png +0 -0
  94. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index_files/index_11_0.png +0 -0
  95. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index_files/index_24_0.png +0 -0
  96. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/d3viz/index_files/index_25_0.png +0 -0
  97. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/gradient.rst +0 -0
  98. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/features.rst +0 -0
  99. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/fgraph.rst +0 -0
  100. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/graph.rst +0 -0
  101. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/index.rst +0 -0
  102. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/op.rst +0 -0
  103. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/type.rst +0 -0
  104. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/graph/utils.rst +0 -0
  105. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/index.rst +0 -0
  106. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/misc/pkl_utils.rst +0 -0
  107. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/printing.rst +0 -0
  108. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/sandbox/index.rst +0 -0
  109. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/sandbox/linalg.rst +0 -0
  110. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/scalar/index.rst +0 -0
  111. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/scan.rst +0 -0
  112. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/sparse/index.rst +0 -0
  113. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/sparse/sandbox.rst +0 -0
  114. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/basic.rst +0 -0
  115. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/basic_opt.rst +0 -0
  116. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/bcast.png +0 -0
  117. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/bcast.svg +0 -0
  118. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/conv.rst +0 -0
  119. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/elemwise.rst +0 -0
  120. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/extra_ops.rst +0 -0
  121. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/fft.rst +0 -0
  122. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/index.rst +0 -0
  123. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/io.rst +0 -0
  124. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/math_opt.rst +0 -0
  125. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/nlinalg.rst +0 -0
  126. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/plot_fft.png +0 -0
  127. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/random/basic.rst +0 -0
  128. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/random/index.rst +0 -0
  129. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/random/utils.rst +0 -0
  130. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/slinalg.rst +0 -0
  131. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/tensor/utils.rst +0 -0
  132. {pytensor-2.24.0 → pytensor-2.24.1}/doc/library/typed_list.rst +0 -0
  133. {pytensor-2.24.0 → pytensor-2.24.1}/doc/links.rst +0 -0
  134. {pytensor-2.24.0 → pytensor-2.24.1}/doc/optimizations.rst +0 -0
  135. {pytensor-2.24.0 → pytensor-2.24.1}/doc/pylintrc +0 -0
  136. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/ccodegen.rst +0 -0
  137. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/compilation.rst +0 -0
  138. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/debugging_with_stepmode.rst +0 -0
  139. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/elemwise_compiler.rst +0 -0
  140. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/function.rst +0 -0
  141. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/functional.rst +0 -0
  142. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/how_to_make_ops.rst +0 -0
  143. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/index.rst +0 -0
  144. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/index2.rst +0 -0
  145. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/interactive_debugger.rst +0 -0
  146. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/logistic_regression_example.rst +0 -0
  147. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/performance.rst +0 -0
  148. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/randomnumbers.rst +0 -0
  149. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/rethinkccodegen.rst +0 -0
  150. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/sandbox.rst +0 -0
  151. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/software.rst +0 -0
  152. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/sparse.rst +0 -0
  153. {pytensor-2.24.0 → pytensor-2.24.1}/doc/sandbox/tensoroptools.rst +0 -0
  154. {pytensor-2.24.0 → pytensor-2.24.1}/doc/troubleshooting.rst +0 -0
  155. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/adding.rst +0 -0
  156. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/adding_solution_1.py +0 -0
  157. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/aliasing.rst +0 -0
  158. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/apply.png +0 -0
  159. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/apply.svg +0 -0
  160. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/bcast.png +0 -0
  161. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/broadcasting.rst +0 -0
  162. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/conditions.rst +0 -0
  163. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/debug_faq.rst +0 -0
  164. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/dlogistic.png +0 -0
  165. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/examples.rst +0 -0
  166. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/faq_tutorial.rst +0 -0
  167. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/gradients.rst +0 -0
  168. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/index.rst +0 -0
  169. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/loading_and_saving.rst +0 -0
  170. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/logistic.gp +0 -0
  171. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/logistic.png +0 -0
  172. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/loop.rst +0 -0
  173. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/loop_solution_1.py +0 -0
  174. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/modes.rst +0 -0
  175. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/modes_solution_1.py +0 -0
  176. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/multi_cores.rst +0 -0
  177. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/nan_tutorial.rst +0 -0
  178. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/pics/d3viz.png +0 -0
  179. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/pics/logreg_pydotprint_predict.png +0 -0
  180. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/pics/logreg_pydotprint_prediction.png +0 -0
  181. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/pics/logreg_pydotprint_train.png +0 -0
  182. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/printing_drawing.rst +0 -0
  183. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/profiling.rst +0 -0
  184. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/profiling_example.py +0 -0
  185. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/profiling_example_out.prof +0 -0
  186. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/shape_info.rst +0 -0
  187. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/sparse.rst +0 -0
  188. {pytensor-2.24.0 → pytensor-2.24.1}/doc/tutorial/symbolic_graphs.rst +0 -0
  189. {pytensor-2.24.0 → pytensor-2.24.1}/doc/user_guide.rst +0 -0
  190. {pytensor-2.24.0 → pytensor-2.24.1}/pyproject.toml +0 -0
  191. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/__init__.py +0 -0
  192. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/bin/__init__.py +0 -0
  193. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/bin/pytensor_cache.py +0 -0
  194. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/breakpoint.py +0 -0
  195. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/__init__.py +0 -0
  196. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/builders.py +0 -0
  197. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/compiledir.py +0 -0
  198. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/compilelock.py +0 -0
  199. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/debugmode.py +0 -0
  200. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/function/__init__.py +0 -0
  201. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/function/pfunc.py +0 -0
  202. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/function/types.py +0 -0
  203. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/io.py +0 -0
  204. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/mode.py +0 -0
  205. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/monitormode.py +0 -0
  206. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/nanguardmode.py +0 -0
  207. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/ops.py +0 -0
  208. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/profiling.py +0 -0
  209. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/compile/sharedvalue.py +0 -0
  210. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/configdefaults.py +0 -0
  211. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/configparser.py +0 -0
  212. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/__init__.py +0 -0
  213. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/css/d3-context-menu.css +0 -0
  214. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/css/d3viz.css +0 -0
  215. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/d3viz.py +0 -0
  216. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/formatting.py +0 -0
  217. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/js/d3-context-menu.js +0 -0
  218. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/js/d3.v3.min.js +0 -0
  219. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/js/d3viz.js +0 -0
  220. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/js/dagre-d3.min.js +0 -0
  221. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/d3viz/js/graphlib-dot.min.js +0 -0
  222. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/gradient.py +0 -0
  223. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/__init__.py +0 -0
  224. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/basic.py +0 -0
  225. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/destroyhandler.py +0 -0
  226. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/features.py +0 -0
  227. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/fg.py +0 -0
  228. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/null_type.py +0 -0
  229. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/op.py +0 -0
  230. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/replace.py +0 -0
  231. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/__init__.py +0 -0
  232. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/basic.py +0 -0
  233. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/db.py +0 -0
  234. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/kanren.py +0 -0
  235. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/unify.py +0 -0
  236. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/rewriting/utils.py +0 -0
  237. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/type.py +0 -0
  238. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/graph/utils.py +0 -0
  239. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/ifelse.py +0 -0
  240. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/__init__.py +0 -0
  241. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/basic.py +0 -0
  242. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/__init__.py +0 -0
  243. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/basic.py +0 -0
  244. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/c_code/lazylinker_c.c +0 -0
  245. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/c_code/pytensor_mod_helper.h +0 -0
  246. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/cmodule.py +0 -0
  247. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/cutils.py +0 -0
  248. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/cvm.py +0 -0
  249. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/exceptions.py +0 -0
  250. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/interface.py +0 -0
  251. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/lazylinker_c.py +0 -0
  252. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/op.py +0 -0
  253. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/params_type.py +0 -0
  254. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/c/type.py +0 -0
  255. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/__init__.py +0 -0
  256. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/__init__.py +0 -0
  257. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/basic.py +0 -0
  258. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/blockwise.py +0 -0
  259. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/elemwise.py +0 -0
  260. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/extra_ops.py +0 -0
  261. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/nlinalg.py +0 -0
  262. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/random.py +0 -0
  263. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/scalar.py +0 -0
  264. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/scan.py +0 -0
  265. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/shape.py +0 -0
  266. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/slinalg.py +0 -0
  267. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/sort.py +0 -0
  268. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/sparse.py +0 -0
  269. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/subtensor.py +0 -0
  270. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/dispatch/tensor_basic.py +0 -0
  271. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/jax/linker.py +0 -0
  272. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/__init__.py +0 -0
  273. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/__init__.py +0 -0
  274. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/basic.py +0 -0
  275. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/cython_support.py +0 -0
  276. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/elemwise.py +0 -0
  277. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/extra_ops.py +0 -0
  278. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/nlinalg.py +0 -0
  279. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/random.py +0 -0
  280. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/scalar.py +0 -0
  281. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/scan.py +0 -0
  282. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/slinalg.py +0 -0
  283. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/sparse.py +0 -0
  284. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/subtensor.py +0 -0
  285. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/tensor_basic.py +0 -0
  286. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/dispatch/vectorize_codegen.py +0 -0
  287. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/numba/linker.py +0 -0
  288. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/pytorch/dispatch/scalar.py +0 -0
  289. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/pytorch/linker.py +0 -0
  290. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/utils.py +0 -0
  291. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/link/vm.py +0 -0
  292. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/__init__.py +0 -0
  293. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/check_blas.py +0 -0
  294. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/check_blas_many.sh +0 -0
  295. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/check_duplicate_key.py +0 -0
  296. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/elemwise_openmp_speedup.py +0 -0
  297. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/elemwise_time_test.py +0 -0
  298. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/frozendict.py +0 -0
  299. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/may_share_memory.py +0 -0
  300. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/ordered_set.py +0 -0
  301. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/pkl_utils.py +0 -0
  302. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/misc/safe_asarray.py +0 -0
  303. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/printing.py +0 -0
  304. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/py.typed +0 -0
  305. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/raise_op.py +0 -0
  306. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/__init__.py +0 -0
  307. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/basic.py +0 -0
  308. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/c_code/Faddeeva.cc +0 -0
  309. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/c_code/Faddeeva.hh +0 -0
  310. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/c_code/gamma.c +0 -0
  311. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/loop.py +0 -0
  312. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/math.py +0 -0
  313. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scalar/sharedvar.py +0 -0
  314. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/__init__.py +0 -0
  315. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/basic.py +0 -0
  316. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/checkpoints.py +0 -0
  317. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/op.py +0 -0
  318. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/rewriting.py +0 -0
  319. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/scan_perform.pyx +0 -0
  320. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/scan_perform_ext.py +0 -0
  321. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/utils.py +0 -0
  322. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/scan/views.py +0 -0
  323. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/__init__.py +0 -0
  324. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/basic.py +0 -0
  325. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/rewriting.py +0 -0
  326. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/sandbox/__init__.py +0 -0
  327. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/sandbox/sp.py +0 -0
  328. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/sandbox/sp2.py +0 -0
  329. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/sharedvar.py +0 -0
  330. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/type.py +0 -0
  331. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/sparse/utils.py +0 -0
  332. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/__init__.py +0 -0
  333. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/basic.py +0 -0
  334. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/blas.py +0 -0
  335. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/blas_c.py +0 -0
  336. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/blas_headers.py +0 -0
  337. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/blas_scipy.py +0 -0
  338. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/blockwise.py +0 -0
  339. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/c_code/alt_blas_common.h +0 -0
  340. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/c_code/alt_blas_template.c +0 -0
  341. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/c_code/dimshuffle.c +0 -0
  342. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/conv/__init__.py +0 -0
  343. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/conv/abstract_conv.py +0 -0
  344. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/elemwise.py +0 -0
  345. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/elemwise_cgen.py +0 -0
  346. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/exceptions.py +0 -0
  347. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/fft.py +0 -0
  348. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/fourier.py +0 -0
  349. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/functional.py +0 -0
  350. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/inplace.py +0 -0
  351. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/io.py +0 -0
  352. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/linalg.py +0 -0
  353. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/math.py +0 -0
  354. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/nlinalg.py +0 -0
  355. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/__init__.py +0 -0
  356. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/basic.py +0 -0
  357. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/op.py +0 -0
  358. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/rewriting/__init__.py +0 -0
  359. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/rewriting/basic.py +0 -0
  360. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/rewriting/jax.py +0 -0
  361. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/rewriting/numba.py +0 -0
  362. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/type.py +0 -0
  363. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/utils.py +0 -0
  364. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/random/var.py +0 -0
  365. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/__init__.py +0 -0
  366. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/basic.py +0 -0
  367. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/blas.py +0 -0
  368. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/blas_c.py +0 -0
  369. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/blas_scipy.py +0 -0
  370. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/blockwise.py +0 -0
  371. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/elemwise.py +0 -0
  372. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/extra_ops.py +0 -0
  373. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/jax.py +0 -0
  374. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/linalg.py +0 -0
  375. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/math.py +0 -0
  376. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/shape.py +0 -0
  377. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/special.py +0 -0
  378. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/subtensor.py +0 -0
  379. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/rewriting/uncanonicalize.py +0 -0
  380. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/shape.py +0 -0
  381. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/sharedvar.py +0 -0
  382. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/slinalg.py +0 -0
  383. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/sort.py +0 -0
  384. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/special.py +0 -0
  385. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/type.py +0 -0
  386. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/type_other.py +0 -0
  387. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/utils.py +0 -0
  388. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/var.py +0 -0
  389. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/variable.py +0 -0
  390. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/tensor/xlogx.py +0 -0
  391. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/typed_list/__init__.py +0 -0
  392. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/typed_list/basic.py +0 -0
  393. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/typed_list/rewriting.py +0 -0
  394. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/typed_list/type.py +0 -0
  395. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/updates.py +0 -0
  396. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/utils.py +0 -0
  397. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor/version.py +0 -0
  398. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/dependency_links.txt +0 -0
  399. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/entry_points.txt +0 -0
  400. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/requires.txt +0 -0
  401. {pytensor-2.24.0 → pytensor-2.24.1}/pytensor.egg-info/top_level.txt +0 -0
  402. {pytensor-2.24.0 → pytensor-2.24.1}/scripts/mypy-failing.txt +0 -0
  403. {pytensor-2.24.0 → pytensor-2.24.1}/setup.cfg +0 -0
  404. {pytensor-2.24.0 → pytensor-2.24.1}/setup.py +0 -0
  405. {pytensor-2.24.0 → pytensor-2.24.1}/tests/link/c/c_code/test_cenum.h +0 -0
  406. {pytensor-2.24.0 → pytensor-2.24.1}/tests/link/c/c_code/test_quadratic_function.c +0 -0
  407. {pytensor-2.24.0 → pytensor-2.24.1}/tests/tensor/conv/c_code/corr3d_gemm.c +0 -0
  408. {pytensor-2.24.0 → pytensor-2.24.1}/tests/tensor/conv/c_code/corr_gemm.c +0 -0
  409. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_breakpoint.py +0 -0
  410. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_config.py +0 -0
  411. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_gradient.py +0 -0
  412. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_ifelse.py +0 -0
  413. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_printing.py +0 -0
  414. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_raise_op.py +0 -0
  415. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_rop.py +0 -0
  416. {pytensor-2.24.0 → pytensor-2.24.1}/tests/test_updates.py +0 -0
  417. {pytensor-2.24.0 → pytensor-2.24.1}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytensor
3
- Version: 2.24.0
3
+ Version: 2.24.1
4
4
  Summary: Optimizing compiler for evaluating mathematical expressions on CPUs and GPUs.
5
5
  Author-email: pymc-devs <pymc.devs@gmail.com>
6
6
  License: .. _license:
@@ -32,8 +32,16 @@ extensions = [
32
32
  "sphinx.ext.napoleon",
33
33
  "sphinx.ext.linkcode",
34
34
  "sphinx.ext.mathjax",
35
+ "sphinx_design",
36
+ "sphinx.ext.intersphinx"
35
37
  ]
36
38
 
39
+ intersphinx_mapping = {
40
+ "jax": ("https://jax.readthedocs.io/en/latest", None),
41
+ "numpy": ("https://numpy.org/doc/stable", None),
42
+ "torch": ("https://pytorch.org/docs/stable", None),
43
+ }
44
+
37
45
  needs_sphinx = "3"
38
46
 
39
47
  todo_include_todos = True
@@ -13,6 +13,7 @@ dependencies:
13
13
  - mock
14
14
  - pillow
15
15
  - pymc-sphinx-theme
16
+ - sphinx-design
16
17
  - pip
17
18
  - pip:
18
19
  - -e ..
@@ -0,0 +1,653 @@
1
+ Adding JAX, Numba and Pytorch support for `Op`\s
2
+ =======================================
3
+
4
+ PyTensor is able to convert its graphs into JAX, Numba and Pytorch compiled functions. In order to do
5
+ this, each :class:`Op` in an PyTensor graph must have an equivalent JAX/Numba/Pytorch implementation function.
6
+
7
+ This tutorial will explain how JAX, Numba and Pytorch implementations are created for an :class:`Op`.
8
+
9
+ Step 1: Identify the PyTensor :class:`Op` you'd like to implement
10
+ ------------------------------------------------------------------------
11
+
12
+ Find the source for the PyTensor :class:`Op` you'd like to be supported and
13
+ identify the function signature and return values. These can be determined by
14
+ looking at the :meth:`Op.make_node` implementation. In general, one needs to be familiar
15
+ with PyTensor :class:`Op`\s in order to provide a conversion implementation, so first read
16
+ :ref:`creating_an_op` if you are not familiar.
17
+
18
+ For example, you want to extend support for :class:`CumsumOp`\:
19
+
20
+ .. code:: python
21
+
22
+ class CumsumOp(Op):
23
+ __props__ = ("axis",)
24
+
25
+ def __new__(typ, *args, **kwargs):
26
+ obj = object.__new__(CumOp, *args, **kwargs)
27
+ obj.mode = "add"
28
+ return obj
29
+
30
+
31
+ :class:`CumsumOp` turns out to be a variant of :class:`CumOp`\ :class:`Op`
32
+ which currently has an :meth:`Op.make_node` as follows:
33
+
34
+ .. code:: python
35
+
36
+ def make_node(self, x):
37
+ x = ptb.as_tensor_variable(x)
38
+ out_type = x.type()
39
+
40
+ if self.axis is None:
41
+ out_type = vector(dtype=x.dtype) # Flatten
42
+ elif self.axis >= x.ndim or self.axis < -x.ndim:
43
+ raise ValueError(f"axis(={self.axis}) out of bounds")
44
+
45
+ return Apply(self, [x], [out_type])
46
+
47
+ The :class:`Apply` instance that's returned specifies the exact types of inputs that
48
+ our implementation will receive and the exact types of outputs it's expected to
49
+ return--both in terms of their data types and number of dimensions/shapes.
50
+ The actual inputs our implementation will receive are necessarily numeric values
51
+ or NumPy :class:`ndarray`\s; all that :meth:`Op.make_node` tells us is the
52
+ general signature of the underlying computation.
53
+
54
+ More specifically, the :class:`Apply` implies that there is one input that is
55
+ automatically converted to PyTensor variables via :func:`as_tensor_variable`.
56
+ There is another parameter, `axis`, that is used to determine the direction
57
+ of the operation, hence shape of the output. The check that follows imply that
58
+ `axis` must refer to a dimension in the input tensor. The input's elements
59
+ could also have any data type (e.g. floats, ints), so our implementation
60
+ must be able to handle all the possible data types.
61
+
62
+ It also tells us that there's only one return value, that it has a data type
63
+ determined by :meth:`x.type()` i.e., the data type of the original tensor.
64
+ This implies that the result is necessarily a matrix.
65
+
66
+ Some class may have a more complex behavior. For example, the :class:`CumOp`\ :class:`Op`
67
+ also has another variant :class:`CumprodOp`\ :class:`Op` with the exact signature
68
+ as :class:`CumsumOp`\ :class:`Op`. The difference lies in that the `mode` attribute in
69
+ :class:`CumOp` definition:
70
+
71
+ .. code:: python
72
+
73
+ class CumOp(COp):
74
+ # See function cumsum/cumprod for docstring
75
+
76
+ __props__ = ("axis", "mode")
77
+ check_input = False
78
+ params_type = ParamsType(
79
+ c_axis=int_t, mode=EnumList(("MODE_ADD", "add"), ("MODE_MUL", "mul"))
80
+ )
81
+
82
+ def __init__(self, axis: int | None = None, mode="add"):
83
+ if mode not in ("add", "mul"):
84
+ raise ValueError(f'{type(self).__name__}: Unknown mode "{mode}"')
85
+ self.axis = axis
86
+ self.mode = mode
87
+
88
+ c_axis = property(lambda self: np.MAXDIMS if self.axis is None else self.axis)
89
+
90
+ `__props__` is used to parametrize the general behavior of the :class:`Op`. One need to
91
+ pay attention to this to decide whether the implementation should support all variants
92
+ or raise an explicit NotImplementedError for cases that are not supported e.g., when
93
+ :class:`CumsumOp` of :class:`CumOp("add")` is supported but not :class:`CumprodOp` of
94
+ :class:`CumOp("mul")`.
95
+
96
+ Next, we look at the :meth:`Op.perform` implementation to see exactly
97
+ how the inputs and outputs are used to compute the outputs for an :class:`Op`
98
+ in Python. This method is effectively what needs to be implemented.
99
+
100
+ Step 2: Find the relevant method in JAX/Numba/Pytorch (or something close)
101
+ ---------------------------------------------------------
102
+
103
+ With a precise idea of what the PyTensor :class:`Op` does we need to figure out how
104
+ to implement it in JAX, Numba or Pytorch. In the best case scenario, there is a similarly named
105
+ function that performs exactly the same computations as the :class:`Op`. For
106
+ example, the :class:`Eye` operator has a JAX equivalent: :func:`jax.numpy.eye`
107
+ and a Pytorch equivalent: :func:`torch.eye`.
108
+
109
+ If we wanted to implement an :class:`Op` like :class:`DimShuffle`, we might need to
110
+ recreate the functionality with some custom logic. In many cases, at least some
111
+ custom logic is needed to reformat the inputs and outputs so that they exactly
112
+ match the `Op`'s.
113
+
114
+ Here's an example for :class:`DimShuffle`:
115
+
116
+
117
+ .. tab-set::
118
+
119
+ .. tab-item:: JAX
120
+
121
+ .. code:: python
122
+
123
+ def dimshuffle(x, op):
124
+ res = jnp.transpose(x, op.transposition)
125
+
126
+ shape = list(res.shape[: len(op.shuffle)])
127
+
128
+ for augm in op.augment:
129
+ shape.insert(augm, 1)
130
+
131
+ res = jnp.reshape(res, shape)
132
+
133
+ if not op.inplace:
134
+ res = jnp.copy(res)
135
+
136
+ return res
137
+
138
+ .. tab-item:: Numba
139
+
140
+ .. code:: python
141
+
142
+ def numba_funcify_DimShuffle(op, node, **kwargs):
143
+ shuffle = tuple(op.shuffle)
144
+ transposition = tuple(op.transposition)
145
+ augment = tuple(op.augment)
146
+ inplace = op.inplace
147
+
148
+ ndim_new_shape = len(shuffle) + len(augment)
149
+
150
+ no_transpose = all(i == j for i, j in enumerate(transposition))
151
+ if no_transpose:
152
+
153
+ @numba_basic.numba_njit
154
+ def transpose(x):
155
+ return x
156
+
157
+ else:
158
+
159
+ @numba_basic.numba_njit
160
+ def transpose(x):
161
+ return np.transpose(x, transposition)
162
+
163
+ shape_template = (1,) * ndim_new_shape
164
+
165
+ # When `len(shuffle) == 0`, the `shuffle_shape[j]` expression below
166
+ # is typed as `getitem(Tuple(), int)`, which has no implementation
167
+ # (since getting an item from an empty sequence doesn't make sense).
168
+ # To avoid this compile-time error, we omit the expression altogether.
169
+ if len(shuffle) > 0:
170
+ # Use the statically known shape if available
171
+ if all(length is not None for length in node.outputs[0].type.shape):
172
+ shape = node.outputs[0].type.shape
173
+
174
+ @numba_basic.numba_njit
175
+ def find_shape(array_shape):
176
+ return shape
177
+
178
+ else:
179
+
180
+ @numba_basic.numba_njit
181
+ def find_shape(array_shape):
182
+ shape = shape_template
183
+ j = 0
184
+ for i in range(ndim_new_shape):
185
+ if i not in augment:
186
+ length = array_shape[j]
187
+ shape = numba_basic.tuple_setitem(shape, i, length)
188
+ j = j + 1
189
+ return shape
190
+
191
+ else:
192
+
193
+ @numba_basic.numba_njit
194
+ def find_shape(array_shape):
195
+ return shape_template
196
+
197
+ if ndim_new_shape > 0:
198
+
199
+ @numba_basic.numba_njit
200
+ def dimshuffle_inner(x, shuffle):
201
+ x = transpose(x)
202
+ shuffle_shape = x.shape[: len(shuffle)]
203
+ new_shape = find_shape(shuffle_shape)
204
+
205
+ # FIXME: Numba's `array.reshape` only accepts C arrays.
206
+ res_reshape = np.reshape(np.ascontiguousarray(x), new_shape)
207
+
208
+ if not inplace:
209
+ return res_reshape.copy()
210
+ else:
211
+ return res_reshape
212
+
213
+ else:
214
+
215
+ @numba_basic.numba_njit
216
+ def dimshuffle_inner(x, shuffle):
217
+ return np.reshape(np.ascontiguousarray(x), ())
218
+
219
+ # Without the following wrapper function we would see this error:
220
+ # E No implementation of function Function(<built-in function getitem>) found for signature:
221
+ # E
222
+ # E >>> getitem(UniTuple(int64 x 2), slice<a:b>)
223
+ # E
224
+ # E There are 22 candidate implementations:
225
+ # E - Of which 22 did not match due to:
226
+ # E Overload of function 'getitem': File: <numerous>: Line N/A.
227
+ # E With argument(s): '(UniTuple(int64 x 2), slice<a:b>)':
228
+ # E No match.
229
+ # ...(on this line)...
230
+ # E shuffle_shape = res.shape[: len(shuffle)]
231
+ @numba_basic.numba_njit(inline="always")
232
+ def dimshuffle(x):
233
+ return dimshuffle_inner(np.asarray(x), shuffle)
234
+
235
+ return dimshuffle
236
+
237
+ .. tab-item:: Pytorch
238
+
239
+ .. code:: python
240
+
241
+ def dimshuffle(x, op):
242
+ res = torch.permute(x, op.transposition)
243
+
244
+ shape = list(res.shape[: len(op.shuffle)])
245
+
246
+ for augm in op.augment:
247
+ shape.insert(augm, 1)
248
+
249
+ res = torch.reshape(res, shape)
250
+
251
+ if not op.inplace:
252
+ res = res.clone()
253
+
254
+ return res
255
+
256
+ In this case, :class:`CumOp` is implemented with NumPy's :func:`numpy.cumsum`
257
+ and :func:`numpy.cumprod`, which have JAX equivalents: :func:`jax.numpy.cumsum`
258
+ and :func:`jax.numpy.cumprod`. The Pytorch equivalents are :func:`torch.cumsum`
259
+ and :func:`torch.cumprod`
260
+
261
+ .. code:: python
262
+
263
+ def perform(self, node, inputs, output_storage):
264
+ x = inputs[0]
265
+ z = output_storage[0]
266
+ if self.mode == "add":
267
+ z[0] = np.cumsum(x, axis=self.axis)
268
+ else:
269
+ z[0] = np.cumprod(x, axis=self.axis)
270
+
271
+ Step 3: Register the function with the respective dispatcher
272
+ ---------------------------------------------------------------
273
+
274
+ With the PyTensor `Op` replicated, we'll need to register the
275
+ function with the backends `Linker`. This is done through the use of
276
+ `singledispatch`. If you don't know how `singledispatch` works, see the
277
+ `Python documentation <https://docs.python.org/3/library/functools.html#functools.singledispatch>`_.
278
+
279
+ The relevant dispatch functions created by `singledispatch` are :func:`pytensor.link.numba.dispatch.numba_funcify`,
280
+ :func:`pytensor.link.jax.dispatch.jax_funcify` and :func:`pytensor.link.pytorch.dispatch.pytorch_funcify`.
281
+
282
+ Here's an example for the `CumOp`\ `Op`:
283
+
284
+ .. tab-set::
285
+
286
+ .. tab-item:: JAX
287
+
288
+ .. code:: python
289
+
290
+ import jax.numpy as jnp
291
+
292
+ from pytensor.tensor.extra_ops import CumOp
293
+ from pytensor.link.jax.dispatch import jax_funcify
294
+
295
+
296
+ @jax_funcify.register(CumOp)
297
+ def jax_funcify_CumOp(op, **kwargs):
298
+ axis = op.axis
299
+ mode = op.mode
300
+
301
+ def cumop(x, axis=axis, mode=mode):
302
+ if mode == "add":
303
+ return jnp.cumsum(x, axis=axis)
304
+ else:
305
+ return jnp.cumprod(x, axis=axis)
306
+
307
+ return cumop
308
+
309
+ Suppose `jnp.cumprod` does not exist, we will need to register the function as follows:
310
+
311
+ .. code:: python
312
+
313
+ import jax.numpy as jnp
314
+
315
+ from pytensor.tensor.extra_ops import CumOp
316
+ from pytensor.link.jax.dispatch import jax_funcify
317
+
318
+
319
+ @jax_funcify.register(CumOp)
320
+ def jax_funcify_CumOp(op, **kwargs):
321
+ axis = op.axis
322
+ mode = op.mode
323
+
324
+ def cumop(x, axis=axis, mode=mode):
325
+ if mode == "add":
326
+ return jnp.cumsum(x, axis=axis)
327
+ else:
328
+ raise NotImplementedError("JAX does not support cumprod function at the moment.")
329
+
330
+ return cumop
331
+
332
+ .. tab-item:: Numba
333
+
334
+ .. code:: python
335
+
336
+ import numpy as np
337
+
338
+ from pytensor import config
339
+ from pytensor.graph import Apply
340
+ from pytensor.link.numba.dispatch import basic as numba_basic
341
+ from pytensor.tensor import TensorVariable
342
+ from pytensor.tensor.extra_ops import CumOp,
343
+
344
+ def numba_funcify_CumOp(op: CumOp, node: Apply, **kwargs):
345
+ axis = op.axis
346
+ mode = op.mode
347
+ ndim = cast(TensorVariable, node.outputs[0]).ndim
348
+
349
+ if axis is not None:
350
+ if axis < 0:
351
+ axis = ndim + axis
352
+ if axis < 0 or axis >= ndim:
353
+ raise ValueError(f"Invalid axis {axis} for array with ndim {ndim}")
354
+
355
+ reaxis_first = (axis, *(i for i in range(ndim) if i != axis))
356
+ reaxis_first_inv = tuple(np.argsort(reaxis_first))
357
+
358
+ if mode == "add":
359
+ if axis is None or ndim == 1:
360
+
361
+ @numba_basic.numba_njit(fastmath=config.numba__fastmath)
362
+ def cumop(x):
363
+ return np.cumsum(x)
364
+
365
+ else:
366
+
367
+ @numba_basic.numba_njit(boundscheck=False, fastmath=config.numba__fastmath)
368
+ def cumop(x):
369
+ out_dtype = x.dtype
370
+ if x.shape[axis] < 2:
371
+ return x.astype(out_dtype)
372
+
373
+ x_axis_first = x.transpose(reaxis_first)
374
+ res = np.empty(x_axis_first.shape, dtype=out_dtype)
375
+
376
+ res[0] = x_axis_first[0]
377
+ for m in range(1, x.shape[axis]):
378
+ res[m] = res[m - 1] + x_axis_first[m]
379
+
380
+ return res.transpose(reaxis_first_inv)
381
+
382
+ else:
383
+ if axis is None or ndim == 1:
384
+
385
+ @numba_basic.numba_njit(fastmath=config.numba__fastmath)
386
+ def cumop(x):
387
+ return np.cumprod(x)
388
+
389
+ else:
390
+
391
+ @numba_basic.numba_njit(boundscheck=False, fastmath=config.numba__fastmath)
392
+ def cumop(x):
393
+ out_dtype = x.dtype
394
+ if x.shape[axis] < 2:
395
+ return x.astype(out_dtype)
396
+
397
+ x_axis_first = x.transpose(reaxis_first)
398
+ res = np.empty(x_axis_first.shape, dtype=out_dtype)
399
+
400
+ res[0] = x_axis_first[0]
401
+ for m in range(1, x.shape[axis]):
402
+ res[m] = res[m - 1] * x_axis_first[m]
403
+
404
+ return res.transpose(reaxis_first)
405
+
406
+ return cumop
407
+
408
+
409
+ .. tab-item:: Pytorch
410
+
411
+ .. code:: python
412
+
413
+ import torch
414
+
415
+ from pytensor.link.pytorch.dispatch.basic import pytorch_funcify
416
+ from pytensor.tensor.extra_ops import CumOp
417
+
418
+
419
+ @pytorch_funcify.register(CumOp)
420
+ def pytorch_funcify_Cumop(op, **kwargs):
421
+ axis = op.axis
422
+ mode = op.mode
423
+
424
+ def cumop(x,):
425
+ if axis is None:
426
+ x = x.reshape(-1)
427
+ dim = 0
428
+ else:
429
+ dim=axis
430
+ if mode == "add":
431
+ return torch.cumsum(x, dim=dim)
432
+ else:
433
+ return torch.cumprod(x, dim=dim)
434
+
435
+ return cumop
436
+
437
+
438
+ Suppose `torch.cumprod` does not exist, we will need to register the function as follows:
439
+
440
+ .. code:: python
441
+
442
+ import torch
443
+
444
+ from pytensor.tensor.extra_ops import CumOp
445
+ from pytensor.link.pytorch.dispatch import pytorch_funcify
446
+
447
+
448
+ @pytorch_funcify.register(CumOp)
449
+ def pytorch_funcify_Cumop(op, **kwargs):
450
+ axis = op.axis
451
+ mode = op.mode
452
+
453
+ def cumop(x, axis=axis, mode=mode):
454
+ if mode == "add":
455
+ return torch.cumsum(x, axis=axis)
456
+ else:
457
+ raise NotImplementedError("Pytorch does not support cumprod function at the moment.")
458
+
459
+ return cumop
460
+
461
+ Step 4: Write tests
462
+ -------------------
463
+ .. tab-set::
464
+
465
+ .. tab-item:: JAX
466
+
467
+ Test that your registered `Op` is working correctly by adding tests to the
468
+ appropriate test suites in PyTensor (e.g. in ``tests.link.jax``).
469
+ The tests should ensure that your implementation can
470
+ handle the appropriate types of inputs and produce outputs equivalent to `Op.perform`.
471
+ Check the existing tests for the general outline of these kinds of tests. In
472
+ most cases, a helper function can be used to easily verify the correspondence
473
+ between a Numba implementation and its `Op`.
474
+
475
+ For example, the :func:`compare_jax_and_py` function streamlines the steps
476
+ involved in making comparisons with `Op.perform`.
477
+
478
+ Here's a small example of a test for :class:`CumOp` above:
479
+
480
+ .. code:: python
481
+
482
+ import numpy as np
483
+ import pytensor.tensor as pt
484
+ from pytensor.configdefaults import config
485
+ from tests.link.jax.test_basic import compare_jax_and_py
486
+ from pytensor.graph import FunctionGraph
487
+ from pytensor.graph.op import get_test_value
488
+
489
+ def test_jax_CumOp():
490
+ """Test JAX conversion of the `CumOp` `Op`."""
491
+
492
+ # Create a symbolic input for the first input of `CumOp`
493
+ a = pt.matrix("a")
494
+
495
+ # Create test value tag for a
496
+ a.tag.test_value = np.arange(9, dtype=config.floatX).reshape((3, 3))
497
+
498
+ # Create the output variable
499
+ out = pt.cumsum(a, axis=0)
500
+
501
+ # Create a PyTensor `FunctionGraph`
502
+ fgraph = FunctionGraph([a], [out])
503
+
504
+ # Pass the graph and inputs to the testing function
505
+ compare_jax_and_py(fgraph, [get_test_value(i) for i in fgraph.inputs])
506
+
507
+ # For the second mode of CumOp
508
+ out = pt.cumprod(a, axis=1)
509
+ fgraph = FunctionGraph([a], [out])
510
+ compare_jax_and_py(fgraph, [get_test_value(i) for i in fgraph.inputs])
511
+
512
+ If the variant :class:`CumprodOp` is not implemented, we can add a test for it as follows:
513
+
514
+ .. code:: python
515
+
516
+ import pytest
517
+
518
+ def test_jax_CumOp():
519
+ """Test JAX conversion of the `CumOp` `Op`."""
520
+ a = pt.matrix("a")
521
+ a.tag.test_value = np.arange(9, dtype=config.floatX).reshape((3, 3))
522
+
523
+ with pytest.raises(NotImplementedError):
524
+ out = pt.cumprod(a, axis=1)
525
+ fgraph = FunctionGraph([a], [out])
526
+ compare_jax_and_py(fgraph, [get_test_value(i) for i in fgraph.inputs])
527
+
528
+
529
+ .. tab-item:: Numba
530
+
531
+ Test that your registered `Op` is working correctly by adding tests to the
532
+ appropriate test suites in PyTensor (e.g. in ``tests.link.numba``).
533
+ The tests should ensure that your implementation can
534
+ handle the appropriate types of inputs and produce outputs equivalent to `Op.perform`.
535
+ Check the existing tests for the general outline of these kinds of tests. In
536
+ most cases, a helper function can be used to easily verify the correspondence
537
+ between a Numba implementation and its `Op`.
538
+
539
+ For example, the :func:`compare_numba_and_py` function streamlines the steps
540
+ involved in making comparisons with `Op.perform`.
541
+
542
+ Here's a small example of a test for :class:`CumOp` above:
543
+
544
+ .. code:: python
545
+
546
+ from tests.link.numba.test_basic import compare_numba_and_py
547
+ from pytensor.graph import FunctionGraph
548
+ from pytensor.compile.sharedvalue import SharedVariable
549
+ from pytensor.graph.basic import Constant
550
+ from pytensor.tensor import extra_ops
551
+
552
+ def test_CumOp(val, axis, mode):
553
+ g = extra_ops.CumOp(axis=axis, mode=mode)(val)
554
+ g_fg = FunctionGraph(outputs=[g])
555
+
556
+ compare_numba_and_py(
557
+ g_fg,
558
+ [
559
+ i.tag.test_value
560
+ for i in g_fg.inputs
561
+ if not isinstance(i, SharedVariable | Constant)
562
+ ],
563
+ )
564
+
565
+
566
+
567
+ .. tab-item:: Pytorch
568
+
569
+ Test that your registered `Op` is working correctly by adding tests to the
570
+ appropriate test suites in PyTensor (``tests.link.pytorch``). The tests should ensure that your implementation can
571
+ handle the appropriate types of inputs and produce outputs equivalent to `Op.perform`.
572
+ Check the existing tests for the general outline of these kinds of tests. In
573
+ most cases, a helper function can be used to easily verify the correspondence
574
+ between a Pytorch implementation and its `Op`.
575
+
576
+ For example, the :func:`compare_pytorch_and_py` function streamlines the steps
577
+ involved in making comparisons with `Op.perform`.
578
+
579
+ Here's a small example of a test for :class:`CumOp` above:
580
+
581
+ .. code:: python
582
+
583
+ import numpy as np
584
+ import pytest
585
+ import pytensor.tensor as pt
586
+ from pytensor.configdefaults import config
587
+ from tests.link.pytorch.test_basic import compare_pytorch_and_py
588
+ from pytensor.graph import FunctionGraph
589
+
590
+ @pytest.mark.parametrize(
591
+ "dtype",
592
+ ["float64", "int64"],
593
+ )
594
+ @pytest.mark.parametrize(
595
+ "axis",
596
+ [None, 1, (0,)],
597
+ )
598
+ def test_pytorch_CumOp(axis, dtype):
599
+ """Test PyTorch conversion of the `CumOp` `Op`."""
600
+
601
+ # Create a symbolic input for the first input of `CumOp`
602
+ a = pt.matrix("a", dtype=dtype)
603
+
604
+ # Create test value
605
+ test_value = np.arange(9, dtype=dtype).reshape((3, 3))
606
+
607
+ # Create the output variable
608
+ if isinstance(axis, tuple):
609
+ with pytest.raises(TypeError, match="axis must be an integer or None."):
610
+ out = pt.cumsum(a, axis=axis)
611
+ with pytest.raises(TypeError, match="axis must be an integer or None."):
612
+ out = pt.cumprod(a, axis=axis)
613
+ else:
614
+ out = pt.cumsum(a, axis=axis)
615
+ # Create a PyTensor `FunctionGraph`
616
+ fgraph = FunctionGraph([a], [out])
617
+
618
+ # Pass the graph and inputs to the testing function
619
+ compare_pytorch_and_py(fgraph, [test_value])
620
+
621
+ # For the second mode of CumOp
622
+ out = pt.cumprod(a, axis=axis)
623
+ fgraph = FunctionGraph([a], [out])
624
+ compare_pytorch_and_py(fgraph, [test_value])
625
+
626
+
627
+ Note
628
+ ----
629
+ In out previous example of extending JAX, :class:`Eye`\ :class:`Op` was used with the test function as follows:
630
+
631
+ .. code:: python
632
+
633
+ def test_jax_Eye():
634
+ """Test JAX conversion of the `Eye` `Op`."""
635
+
636
+ # Create a symbolic input for `Eye`
637
+ x_at = pt.scalar()
638
+
639
+ # Create a variable that is the output of an `Eye` `Op`
640
+ eye_var = pt.eye(x_at)
641
+
642
+ # Create an PyTensor `FunctionGraph`
643
+ out_fg = FunctionGraph(outputs=[eye_var])
644
+
645
+ # Pass the graph and any inputs to the testing function
646
+ compare_jax_and_py(out_fg, [3])
647
+
648
+ This one nowadays leads to a test failure due to new restrictions in JAX + JIT,
649
+ as reported in issue `#654 <https://github.com/pymc-devs/pytensor/issues/654>`_.
650
+ All jitted functions now must have constant shape, which means a graph like the
651
+ one of :class:`Eye` can never be translated to JAX, since it's fundamentally a
652
+ function with dynamic shapes. In other words, only PyTensor graphs with static shapes
653
+ can be translated to JAX at the moment.