passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.whl

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 (719) hide show
  1. passagemath_categories-10.6.32.dist-info/METADATA +156 -0
  2. passagemath_categories-10.6.32.dist-info/RECORD +719 -0
  3. passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
  4. passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
  5. passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
  6. passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
  7. passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
  8. sage/all__sagemath_categories.py +28 -0
  9. sage/arith/all.py +38 -0
  10. sage/arith/constants.pxd +27 -0
  11. sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
  12. sage/arith/functions.pxd +4 -0
  13. sage/arith/functions.pyx +221 -0
  14. sage/arith/misc.py +6552 -0
  15. sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
  16. sage/arith/multi_modular.pxd +39 -0
  17. sage/arith/multi_modular.pyx +994 -0
  18. sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
  19. sage/arith/rational_reconstruction.pxd +4 -0
  20. sage/arith/rational_reconstruction.pyx +115 -0
  21. sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
  22. sage/arith/srange.pyx +571 -0
  23. sage/calculus/all__sagemath_categories.py +2 -0
  24. sage/calculus/functional.py +481 -0
  25. sage/calculus/functions.py +151 -0
  26. sage/categories/additive_groups.py +73 -0
  27. sage/categories/additive_magmas.py +1044 -0
  28. sage/categories/additive_monoids.py +114 -0
  29. sage/categories/additive_semigroups.py +184 -0
  30. sage/categories/affine_weyl_groups.py +238 -0
  31. sage/categories/algebra_ideals.py +95 -0
  32. sage/categories/algebra_modules.py +96 -0
  33. sage/categories/algebras.py +349 -0
  34. sage/categories/algebras_with_basis.py +377 -0
  35. sage/categories/all.py +160 -0
  36. sage/categories/aperiodic_semigroups.py +29 -0
  37. sage/categories/associative_algebras.py +47 -0
  38. sage/categories/bialgebras.py +101 -0
  39. sage/categories/bialgebras_with_basis.py +414 -0
  40. sage/categories/bimodules.py +206 -0
  41. sage/categories/chain_complexes.py +268 -0
  42. sage/categories/classical_crystals.py +480 -0
  43. sage/categories/coalgebras.py +405 -0
  44. sage/categories/coalgebras_with_basis.py +232 -0
  45. sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
  46. sage/categories/coercion_methods.pyx +52 -0
  47. sage/categories/commutative_additive_groups.py +104 -0
  48. sage/categories/commutative_additive_monoids.py +45 -0
  49. sage/categories/commutative_additive_semigroups.py +48 -0
  50. sage/categories/commutative_algebra_ideals.py +87 -0
  51. sage/categories/commutative_algebras.py +94 -0
  52. sage/categories/commutative_ring_ideals.py +58 -0
  53. sage/categories/commutative_rings.py +736 -0
  54. sage/categories/complete_discrete_valuation.py +293 -0
  55. sage/categories/complex_reflection_groups.py +145 -0
  56. sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
  57. sage/categories/coxeter_group_algebras.py +186 -0
  58. sage/categories/coxeter_groups.py +3402 -0
  59. sage/categories/crystals.py +2628 -0
  60. sage/categories/cw_complexes.py +216 -0
  61. sage/categories/dedekind_domains.py +137 -0
  62. sage/categories/discrete_valuation.py +325 -0
  63. sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
  64. sage/categories/division_rings.py +114 -0
  65. sage/categories/domains.py +95 -0
  66. sage/categories/drinfeld_modules.py +789 -0
  67. sage/categories/dual.py +42 -0
  68. sage/categories/enumerated_sets.py +1146 -0
  69. sage/categories/euclidean_domains.py +271 -0
  70. sage/categories/examples/algebras_with_basis.py +102 -0
  71. sage/categories/examples/all.py +1 -0
  72. sage/categories/examples/commutative_additive_monoids.py +130 -0
  73. sage/categories/examples/commutative_additive_semigroups.py +199 -0
  74. sage/categories/examples/coxeter_groups.py +8 -0
  75. sage/categories/examples/crystals.py +236 -0
  76. sage/categories/examples/cw_complexes.py +163 -0
  77. sage/categories/examples/facade_sets.py +187 -0
  78. sage/categories/examples/filtered_algebras_with_basis.py +204 -0
  79. sage/categories/examples/filtered_modules_with_basis.py +154 -0
  80. sage/categories/examples/finite_coxeter_groups.py +252 -0
  81. sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
  82. sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
  83. sage/categories/examples/finite_enumerated_sets.py +208 -0
  84. sage/categories/examples/finite_monoids.py +150 -0
  85. sage/categories/examples/finite_semigroups.py +190 -0
  86. sage/categories/examples/finite_weyl_groups.py +191 -0
  87. sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
  88. sage/categories/examples/graded_modules_with_basis.py +168 -0
  89. sage/categories/examples/graphs.py +122 -0
  90. sage/categories/examples/hopf_algebras_with_basis.py +145 -0
  91. sage/categories/examples/infinite_enumerated_sets.py +190 -0
  92. sage/categories/examples/lie_algebras.py +352 -0
  93. sage/categories/examples/lie_algebras_with_basis.py +196 -0
  94. sage/categories/examples/magmas.py +162 -0
  95. sage/categories/examples/manifolds.py +94 -0
  96. sage/categories/examples/monoids.py +144 -0
  97. sage/categories/examples/posets.py +178 -0
  98. sage/categories/examples/semigroups.py +580 -0
  99. sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
  100. sage/categories/examples/semigroups_cython.pyx +221 -0
  101. sage/categories/examples/semirings.py +249 -0
  102. sage/categories/examples/sets_cat.py +706 -0
  103. sage/categories/examples/sets_with_grading.py +101 -0
  104. sage/categories/examples/with_realizations.py +542 -0
  105. sage/categories/fields.py +991 -0
  106. sage/categories/filtered_algebras.py +63 -0
  107. sage/categories/filtered_algebras_with_basis.py +548 -0
  108. sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
  109. sage/categories/filtered_modules.py +210 -0
  110. sage/categories/filtered_modules_with_basis.py +1209 -0
  111. sage/categories/finite_complex_reflection_groups.py +1506 -0
  112. sage/categories/finite_coxeter_groups.py +1138 -0
  113. sage/categories/finite_crystals.py +103 -0
  114. sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
  115. sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
  116. sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
  117. sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
  118. sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
  119. sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
  120. sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
  121. sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
  122. sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
  123. sage/categories/finite_enumerated_sets.py +769 -0
  124. sage/categories/finite_fields.py +252 -0
  125. sage/categories/finite_groups.py +256 -0
  126. sage/categories/finite_lattice_posets.py +242 -0
  127. sage/categories/finite_monoids.py +316 -0
  128. sage/categories/finite_permutation_groups.py +339 -0
  129. sage/categories/finite_posets.py +1994 -0
  130. sage/categories/finite_semigroups.py +136 -0
  131. sage/categories/finite_sets.py +93 -0
  132. sage/categories/finite_weyl_groups.py +39 -0
  133. sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
  134. sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
  135. sage/categories/finitely_generated_magmas.py +57 -0
  136. sage/categories/finitely_generated_semigroups.py +214 -0
  137. sage/categories/function_fields.py +76 -0
  138. sage/categories/g_sets.py +77 -0
  139. sage/categories/gcd_domains.py +65 -0
  140. sage/categories/generalized_coxeter_groups.py +94 -0
  141. sage/categories/graded_algebras.py +85 -0
  142. sage/categories/graded_algebras_with_basis.py +258 -0
  143. sage/categories/graded_bialgebras.py +32 -0
  144. sage/categories/graded_bialgebras_with_basis.py +32 -0
  145. sage/categories/graded_coalgebras.py +65 -0
  146. sage/categories/graded_coalgebras_with_basis.py +51 -0
  147. sage/categories/graded_hopf_algebras.py +41 -0
  148. sage/categories/graded_hopf_algebras_with_basis.py +169 -0
  149. sage/categories/graded_lie_algebras.py +91 -0
  150. sage/categories/graded_lie_algebras_with_basis.py +44 -0
  151. sage/categories/graded_lie_conformal_algebras.py +74 -0
  152. sage/categories/graded_modules.py +133 -0
  153. sage/categories/graded_modules_with_basis.py +329 -0
  154. sage/categories/graphs.py +138 -0
  155. sage/categories/group_algebras.py +430 -0
  156. sage/categories/groupoid.py +94 -0
  157. sage/categories/groups.py +667 -0
  158. sage/categories/h_trivial_semigroups.py +64 -0
  159. sage/categories/hecke_modules.py +185 -0
  160. sage/categories/highest_weight_crystals.py +980 -0
  161. sage/categories/hopf_algebras.py +219 -0
  162. sage/categories/hopf_algebras_with_basis.py +309 -0
  163. sage/categories/infinite_enumerated_sets.py +115 -0
  164. sage/categories/integral_domains.py +203 -0
  165. sage/categories/j_trivial_semigroups.py +29 -0
  166. sage/categories/kac_moody_algebras.py +82 -0
  167. sage/categories/kahler_algebras.py +203 -0
  168. sage/categories/l_trivial_semigroups.py +63 -0
  169. sage/categories/lambda_bracket_algebras.py +280 -0
  170. sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
  171. sage/categories/lattice_posets.py +89 -0
  172. sage/categories/left_modules.py +49 -0
  173. sage/categories/lie_algebras.py +1070 -0
  174. sage/categories/lie_algebras_with_basis.py +261 -0
  175. sage/categories/lie_conformal_algebras.py +350 -0
  176. sage/categories/lie_conformal_algebras_with_basis.py +147 -0
  177. sage/categories/lie_groups.py +73 -0
  178. sage/categories/loop_crystals.py +1290 -0
  179. sage/categories/magmas.py +1189 -0
  180. sage/categories/magmas_and_additive_magmas.py +149 -0
  181. sage/categories/magmatic_algebras.py +365 -0
  182. sage/categories/manifolds.py +352 -0
  183. sage/categories/matrix_algebras.py +40 -0
  184. sage/categories/metric_spaces.py +387 -0
  185. sage/categories/modular_abelian_varieties.py +78 -0
  186. sage/categories/modules.py +989 -0
  187. sage/categories/modules_with_basis.py +2794 -0
  188. sage/categories/monoid_algebras.py +38 -0
  189. sage/categories/monoids.py +739 -0
  190. sage/categories/noetherian_rings.py +87 -0
  191. sage/categories/number_fields.py +242 -0
  192. sage/categories/ore_modules.py +189 -0
  193. sage/categories/partially_ordered_monoids.py +49 -0
  194. sage/categories/permutation_groups.py +63 -0
  195. sage/categories/pointed_sets.py +42 -0
  196. sage/categories/polyhedra.py +74 -0
  197. sage/categories/poor_man_map.py +270 -0
  198. sage/categories/posets.py +722 -0
  199. sage/categories/principal_ideal_domains.py +270 -0
  200. sage/categories/quantum_group_representations.py +543 -0
  201. sage/categories/quotient_fields.py +728 -0
  202. sage/categories/r_trivial_semigroups.py +45 -0
  203. sage/categories/regular_crystals.py +898 -0
  204. sage/categories/regular_supercrystals.py +170 -0
  205. sage/categories/right_modules.py +49 -0
  206. sage/categories/ring_ideals.py +74 -0
  207. sage/categories/rings.py +1904 -0
  208. sage/categories/rngs.py +175 -0
  209. sage/categories/schemes.py +393 -0
  210. sage/categories/semigroups.py +1060 -0
  211. sage/categories/semirings.py +71 -0
  212. sage/categories/semisimple_algebras.py +114 -0
  213. sage/categories/sets_with_grading.py +235 -0
  214. sage/categories/shephard_groups.py +43 -0
  215. sage/categories/signed_tensor.py +120 -0
  216. sage/categories/simplicial_complexes.py +134 -0
  217. sage/categories/simplicial_sets.py +1206 -0
  218. sage/categories/super_algebras.py +149 -0
  219. sage/categories/super_algebras_with_basis.py +144 -0
  220. sage/categories/super_hopf_algebras_with_basis.py +126 -0
  221. sage/categories/super_lie_conformal_algebras.py +193 -0
  222. sage/categories/super_modules.py +229 -0
  223. sage/categories/super_modules_with_basis.py +193 -0
  224. sage/categories/supercommutative_algebras.py +99 -0
  225. sage/categories/supercrystals.py +406 -0
  226. sage/categories/tensor.py +110 -0
  227. sage/categories/topological_spaces.py +170 -0
  228. sage/categories/triangular_kac_moody_algebras.py +439 -0
  229. sage/categories/tutorial.py +58 -0
  230. sage/categories/unique_factorization_domains.py +318 -0
  231. sage/categories/unital_algebras.py +426 -0
  232. sage/categories/vector_bundles.py +159 -0
  233. sage/categories/vector_spaces.py +357 -0
  234. sage/categories/weyl_groups.py +853 -0
  235. sage/combinat/all__sagemath_categories.py +34 -0
  236. sage/combinat/backtrack.py +180 -0
  237. sage/combinat/combinat.py +2269 -0
  238. sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
  239. sage/combinat/combinat_cython.pxd +6 -0
  240. sage/combinat/combinat_cython.pyx +390 -0
  241. sage/combinat/combination.py +796 -0
  242. sage/combinat/combinatorial_map.py +416 -0
  243. sage/combinat/composition.py +2192 -0
  244. sage/combinat/dlx.py +510 -0
  245. sage/combinat/integer_lists/__init__.py +7 -0
  246. sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
  247. sage/combinat/integer_lists/base.pxd +16 -0
  248. sage/combinat/integer_lists/base.pyx +713 -0
  249. sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
  250. sage/combinat/integer_lists/invlex.pxd +4 -0
  251. sage/combinat/integer_lists/invlex.pyx +1650 -0
  252. sage/combinat/integer_lists/lists.py +328 -0
  253. sage/combinat/integer_lists/nn.py +48 -0
  254. sage/combinat/integer_vector.py +1818 -0
  255. sage/combinat/integer_vector_weighted.py +413 -0
  256. sage/combinat/matrices/all__sagemath_categories.py +5 -0
  257. sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
  258. sage/combinat/matrices/dancing_links.pyx +1159 -0
  259. sage/combinat/matrices/dancing_links_c.h +380 -0
  260. sage/combinat/matrices/dlxcpp.py +136 -0
  261. sage/combinat/partition.py +10070 -0
  262. sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
  263. sage/combinat/partitions.pyx +743 -0
  264. sage/combinat/permutation.py +10168 -0
  265. sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
  266. sage/combinat/permutation_cython.pxd +11 -0
  267. sage/combinat/permutation_cython.pyx +407 -0
  268. sage/combinat/q_analogues.py +1090 -0
  269. sage/combinat/ranker.py +268 -0
  270. sage/combinat/subset.py +1561 -0
  271. sage/combinat/subsets_hereditary.py +202 -0
  272. sage/combinat/subsets_pairwise.py +184 -0
  273. sage/combinat/tools.py +63 -0
  274. sage/combinat/tuple.py +348 -0
  275. sage/data_structures/all.py +2 -0
  276. sage/data_structures/all__sagemath_categories.py +2 -0
  277. sage/data_structures/binary_matrix.pxd +138 -0
  278. sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
  279. sage/data_structures/binary_search.pxd +3 -0
  280. sage/data_structures/binary_search.pyx +66 -0
  281. sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
  282. sage/data_structures/bitset.pxd +40 -0
  283. sage/data_structures/bitset.pyx +2385 -0
  284. sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
  285. sage/data_structures/bitset_base.pxd +926 -0
  286. sage/data_structures/bitset_base.pyx +117 -0
  287. sage/data_structures/bitset_intrinsics.h +487 -0
  288. sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
  289. sage/data_structures/blas_dict.pxd +12 -0
  290. sage/data_structures/blas_dict.pyx +469 -0
  291. sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
  292. sage/data_structures/list_of_pairs.pxd +16 -0
  293. sage/data_structures/list_of_pairs.pyx +122 -0
  294. sage/data_structures/mutable_poset.py +3312 -0
  295. sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
  296. sage/data_structures/pairing_heap.h +346 -0
  297. sage/data_structures/pairing_heap.pxd +88 -0
  298. sage/data_structures/pairing_heap.pyx +1464 -0
  299. sage/data_structures/sparse_bitset.pxd +62 -0
  300. sage/data_structures/stream.py +5070 -0
  301. sage/databases/all__sagemath_categories.py +7 -0
  302. sage/databases/sql_db.py +2236 -0
  303. sage/ext/all__sagemath_categories.py +3 -0
  304. sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
  305. sage/ext/fast_callable.pxd +4 -0
  306. sage/ext/fast_callable.pyx +2746 -0
  307. sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
  308. sage/ext/fast_eval.pxd +1 -0
  309. sage/ext/fast_eval.pyx +102 -0
  310. sage/ext/interpreters/__init__.py +1 -0
  311. sage/ext/interpreters/all__sagemath_categories.py +2 -0
  312. sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
  313. sage/ext/interpreters/wrapper_el.pxd +18 -0
  314. sage/ext/interpreters/wrapper_el.pyx +148 -0
  315. sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
  316. sage/ext/interpreters/wrapper_py.pxd +17 -0
  317. sage/ext/interpreters/wrapper_py.pyx +133 -0
  318. sage/functions/airy.py +937 -0
  319. sage/functions/all.py +97 -0
  320. sage/functions/bessel.py +2102 -0
  321. sage/functions/error.py +784 -0
  322. sage/functions/exp_integral.py +1529 -0
  323. sage/functions/gamma.py +1087 -0
  324. sage/functions/generalized.py +672 -0
  325. sage/functions/hyperbolic.py +747 -0
  326. sage/functions/hypergeometric.py +1156 -0
  327. sage/functions/jacobi.py +1705 -0
  328. sage/functions/log.py +1402 -0
  329. sage/functions/min_max.py +338 -0
  330. sage/functions/orthogonal_polys.py +3106 -0
  331. sage/functions/other.py +2303 -0
  332. sage/functions/piecewise.py +1505 -0
  333. sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
  334. sage/functions/prime_pi.pyx +262 -0
  335. sage/functions/special.py +1212 -0
  336. sage/functions/spike_function.py +278 -0
  337. sage/functions/transcendental.py +690 -0
  338. sage/functions/trig.py +1062 -0
  339. sage/functions/wigner.py +726 -0
  340. sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
  341. sage/geometry/abc.pyx +82 -0
  342. sage/geometry/all__sagemath_categories.py +1 -0
  343. sage/groups/all__sagemath_categories.py +11 -0
  344. sage/groups/generic.py +1733 -0
  345. sage/groups/groups_catalog.py +113 -0
  346. sage/groups/perm_gps/all__sagemath_categories.py +1 -0
  347. sage/groups/perm_gps/partn_ref/all.py +1 -0
  348. sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
  349. sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
  350. sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
  351. sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
  352. sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
  353. sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
  354. sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
  355. sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
  356. sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
  357. sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
  358. sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
  359. sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
  360. sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
  361. sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
  362. sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
  363. sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
  364. sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
  365. sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
  366. sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
  367. sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
  368. sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
  369. sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
  370. sage/interfaces/abc.py +140 -0
  371. sage/interfaces/all.py +58 -0
  372. sage/interfaces/all__sagemath_categories.py +1 -0
  373. sage/interfaces/expect.py +1643 -0
  374. sage/interfaces/interface.py +1682 -0
  375. sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
  376. sage/interfaces/process.pxd +5 -0
  377. sage/interfaces/process.pyx +288 -0
  378. sage/interfaces/quit.py +167 -0
  379. sage/interfaces/sage0.py +604 -0
  380. sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
  381. sage/interfaces/sagespawn.pyx +308 -0
  382. sage/interfaces/tab_completion.py +101 -0
  383. sage/misc/all__sagemath_categories.py +78 -0
  384. sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
  385. sage/misc/allocator.pxd +6 -0
  386. sage/misc/allocator.pyx +47 -0
  387. sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
  388. sage/misc/binary_tree.pxd +29 -0
  389. sage/misc/binary_tree.pyx +537 -0
  390. sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
  391. sage/misc/callable_dict.pyx +89 -0
  392. sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
  393. sage/misc/citation.pyx +159 -0
  394. sage/misc/converting_dict.py +293 -0
  395. sage/misc/defaults.py +129 -0
  396. sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
  397. sage/misc/derivative.pyx +223 -0
  398. sage/misc/functional.py +2005 -0
  399. sage/misc/html.py +589 -0
  400. sage/misc/latex.py +2673 -0
  401. sage/misc/latex_macros.py +236 -0
  402. sage/misc/latex_standalone.py +1833 -0
  403. sage/misc/map_threaded.py +38 -0
  404. sage/misc/mathml.py +76 -0
  405. sage/misc/method_decorator.py +88 -0
  406. sage/misc/mrange.py +755 -0
  407. sage/misc/multireplace.py +41 -0
  408. sage/misc/object_multiplexer.py +92 -0
  409. sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
  410. sage/misc/parser.pyx +1107 -0
  411. sage/misc/random_testing.py +264 -0
  412. sage/misc/rest_index_of_methods.py +377 -0
  413. sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
  414. sage/misc/search.pxd +2 -0
  415. sage/misc/search.pyx +68 -0
  416. sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
  417. sage/misc/stopgap.pyx +95 -0
  418. sage/misc/table.py +853 -0
  419. sage/monoids/all__sagemath_categories.py +1 -0
  420. sage/monoids/indexed_free_monoid.py +1071 -0
  421. sage/monoids/monoid.py +82 -0
  422. sage/numerical/all__sagemath_categories.py +1 -0
  423. sage/numerical/backends/all__sagemath_categories.py +1 -0
  424. sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
  425. sage/numerical/backends/generic_backend.pxd +61 -0
  426. sage/numerical/backends/generic_backend.pyx +1893 -0
  427. sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
  428. sage/numerical/backends/generic_sdp_backend.pxd +38 -0
  429. sage/numerical/backends/generic_sdp_backend.pyx +755 -0
  430. sage/parallel/all.py +6 -0
  431. sage/parallel/decorate.py +575 -0
  432. sage/parallel/map_reduce.py +1997 -0
  433. sage/parallel/multiprocessing_sage.py +76 -0
  434. sage/parallel/ncpus.py +35 -0
  435. sage/parallel/parallelism.py +364 -0
  436. sage/parallel/reference.py +47 -0
  437. sage/parallel/use_fork.py +333 -0
  438. sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
  439. sage/rings/abc.pxd +31 -0
  440. sage/rings/abc.pyx +526 -0
  441. sage/rings/algebraic_closure_finite_field.py +1154 -0
  442. sage/rings/all__sagemath_categories.py +91 -0
  443. sage/rings/big_oh.py +227 -0
  444. sage/rings/continued_fraction.py +2754 -0
  445. sage/rings/continued_fraction_gosper.py +220 -0
  446. sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
  447. sage/rings/factorint.pyx +295 -0
  448. sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
  449. sage/rings/fast_arith.pxd +21 -0
  450. sage/rings/fast_arith.pyx +535 -0
  451. sage/rings/finite_rings/all__sagemath_categories.py +9 -0
  452. sage/rings/finite_rings/conway_polynomials.py +542 -0
  453. sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
  454. sage/rings/finite_rings/element_base.pxd +12 -0
  455. sage/rings/finite_rings/element_base.pyx +1176 -0
  456. sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
  457. sage/rings/finite_rings/finite_field_base.pxd +7 -0
  458. sage/rings/finite_rings/finite_field_base.pyx +2171 -0
  459. sage/rings/finite_rings/finite_field_constructor.py +827 -0
  460. sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
  461. sage/rings/finite_rings/galois_group.py +154 -0
  462. sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
  463. sage/rings/finite_rings/hom_finite_field.pxd +23 -0
  464. sage/rings/finite_rings/hom_finite_field.pyx +856 -0
  465. sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
  466. sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
  467. sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
  468. sage/rings/finite_rings/homset.py +357 -0
  469. sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
  470. sage/rings/finite_rings/integer_mod.pxd +56 -0
  471. sage/rings/finite_rings/integer_mod.pyx +4586 -0
  472. sage/rings/finite_rings/integer_mod_limits.h +11 -0
  473. sage/rings/finite_rings/integer_mod_ring.py +2044 -0
  474. sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
  475. sage/rings/finite_rings/residue_field.pxd +30 -0
  476. sage/rings/finite_rings/residue_field.pyx +1811 -0
  477. sage/rings/finite_rings/stdint.pxd +19 -0
  478. sage/rings/fraction_field.py +1452 -0
  479. sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
  480. sage/rings/fraction_field_element.pyx +1357 -0
  481. sage/rings/function_field/all.py +7 -0
  482. sage/rings/function_field/all__sagemath_categories.py +2 -0
  483. sage/rings/function_field/constructor.py +218 -0
  484. sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
  485. sage/rings/function_field/element.pxd +11 -0
  486. sage/rings/function_field/element.pyx +1008 -0
  487. sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
  488. sage/rings/function_field/element_rational.pyx +513 -0
  489. sage/rings/function_field/extensions.py +230 -0
  490. sage/rings/function_field/function_field.py +1468 -0
  491. sage/rings/function_field/function_field_rational.py +1005 -0
  492. sage/rings/function_field/ideal.py +1155 -0
  493. sage/rings/function_field/ideal_rational.py +629 -0
  494. sage/rings/function_field/jacobian_base.py +826 -0
  495. sage/rings/function_field/jacobian_hess.py +1053 -0
  496. sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
  497. sage/rings/function_field/maps.py +1039 -0
  498. sage/rings/function_field/order.py +281 -0
  499. sage/rings/function_field/order_basis.py +586 -0
  500. sage/rings/function_field/order_rational.py +576 -0
  501. sage/rings/function_field/place.py +426 -0
  502. sage/rings/function_field/place_rational.py +181 -0
  503. sage/rings/generic.py +320 -0
  504. sage/rings/homset.py +332 -0
  505. sage/rings/ideal.py +1885 -0
  506. sage/rings/ideal_monoid.py +215 -0
  507. sage/rings/infinity.py +1890 -0
  508. sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
  509. sage/rings/integer.pxd +45 -0
  510. sage/rings/integer.pyx +7874 -0
  511. sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
  512. sage/rings/integer_ring.pxd +8 -0
  513. sage/rings/integer_ring.pyx +1693 -0
  514. sage/rings/laurent_series_ring.py +931 -0
  515. sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
  516. sage/rings/laurent_series_ring_element.pxd +11 -0
  517. sage/rings/laurent_series_ring_element.pyx +1927 -0
  518. sage/rings/lazy_series.py +7815 -0
  519. sage/rings/lazy_series_ring.py +4356 -0
  520. sage/rings/localization.py +1043 -0
  521. sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
  522. sage/rings/morphism.pxd +39 -0
  523. sage/rings/morphism.pyx +3299 -0
  524. sage/rings/multi_power_series_ring.py +1145 -0
  525. sage/rings/multi_power_series_ring_element.py +2184 -0
  526. sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
  527. sage/rings/noncommutative_ideals.pyx +423 -0
  528. sage/rings/number_field/all__sagemath_categories.py +1 -0
  529. sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
  530. sage/rings/number_field/number_field_base.pxd +8 -0
  531. sage/rings/number_field/number_field_base.pyx +507 -0
  532. sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
  533. sage/rings/number_field/number_field_element_base.pxd +6 -0
  534. sage/rings/number_field/number_field_element_base.pyx +36 -0
  535. sage/rings/number_field/number_field_ideal.py +3550 -0
  536. sage/rings/padics/all__sagemath_categories.py +4 -0
  537. sage/rings/padics/local_generic.py +1670 -0
  538. sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
  539. sage/rings/padics/local_generic_element.pxd +5 -0
  540. sage/rings/padics/local_generic_element.pyx +1017 -0
  541. sage/rings/padics/misc.py +256 -0
  542. sage/rings/padics/padic_generic.py +1911 -0
  543. sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
  544. sage/rings/padics/pow_computer.pxd +38 -0
  545. sage/rings/padics/pow_computer.pyx +671 -0
  546. sage/rings/padics/precision_error.py +24 -0
  547. sage/rings/polynomial/all__sagemath_categories.py +25 -0
  548. sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
  549. sage/rings/polynomial/commutative_polynomial.pxd +6 -0
  550. sage/rings/polynomial/commutative_polynomial.pyx +24 -0
  551. sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
  552. sage/rings/polynomial/cyclotomic.pyx +404 -0
  553. sage/rings/polynomial/flatten.py +711 -0
  554. sage/rings/polynomial/ideal.py +102 -0
  555. sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
  556. sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
  557. sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
  558. sage/rings/polynomial/laurent_polynomial.pxd +18 -0
  559. sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
  560. sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
  561. sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
  562. sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
  563. sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
  564. sage/rings/polynomial/multi_polynomial.pxd +12 -0
  565. sage/rings/polynomial/multi_polynomial.pyx +3082 -0
  566. sage/rings/polynomial/multi_polynomial_element.py +2570 -0
  567. sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
  568. sage/rings/polynomial/multi_polynomial_ring.py +947 -0
  569. sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
  570. sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
  571. sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
  572. sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
  573. sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
  574. sage/rings/polynomial/polydict.pxd +45 -0
  575. sage/rings/polynomial/polydict.pyx +2701 -0
  576. sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
  577. sage/rings/polynomial/polynomial_compiled.pxd +59 -0
  578. sage/rings/polynomial/polynomial_compiled.pyx +509 -0
  579. sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
  580. sage/rings/polynomial/polynomial_element.pxd +64 -0
  581. sage/rings/polynomial/polynomial_element.pyx +13255 -0
  582. sage/rings/polynomial/polynomial_element_generic.py +1637 -0
  583. sage/rings/polynomial/polynomial_fateman.py +97 -0
  584. sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
  585. sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
  586. sage/rings/polynomial/polynomial_ring.py +3784 -0
  587. sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
  588. sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
  589. sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
  590. sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
  591. sage/rings/polynomial/polynomial_singular_interface.py +549 -0
  592. sage/rings/polynomial/symmetric_ideal.py +989 -0
  593. sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
  594. sage/rings/polynomial/symmetric_reduction.pxd +8 -0
  595. sage/rings/polynomial/symmetric_reduction.pyx +669 -0
  596. sage/rings/polynomial/term_order.py +2279 -0
  597. sage/rings/polynomial/toy_buchberger.py +449 -0
  598. sage/rings/polynomial/toy_d_basis.py +387 -0
  599. sage/rings/polynomial/toy_variety.py +362 -0
  600. sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
  601. sage/rings/power_series_mpoly.pxd +9 -0
  602. sage/rings/power_series_mpoly.pyx +161 -0
  603. sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
  604. sage/rings/power_series_poly.pxd +10 -0
  605. sage/rings/power_series_poly.pyx +1317 -0
  606. sage/rings/power_series_ring.py +1441 -0
  607. sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
  608. sage/rings/power_series_ring_element.pxd +12 -0
  609. sage/rings/power_series_ring_element.pyx +3028 -0
  610. sage/rings/puiseux_series_ring.py +487 -0
  611. sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
  612. sage/rings/puiseux_series_ring_element.pxd +7 -0
  613. sage/rings/puiseux_series_ring_element.pyx +1055 -0
  614. sage/rings/qqbar_decorators.py +167 -0
  615. sage/rings/quotient_ring.py +1598 -0
  616. sage/rings/quotient_ring_element.py +979 -0
  617. sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
  618. sage/rings/rational.pxd +20 -0
  619. sage/rings/rational.pyx +4284 -0
  620. sage/rings/rational_field.py +1730 -0
  621. sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
  622. sage/rings/real_double.pxd +16 -0
  623. sage/rings/real_double.pyx +2218 -0
  624. sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
  625. sage/rings/real_lazy.pxd +30 -0
  626. sage/rings/real_lazy.pyx +1773 -0
  627. sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
  628. sage/rings/ring.pxd +30 -0
  629. sage/rings/ring.pyx +850 -0
  630. sage/rings/semirings/all.py +3 -0
  631. sage/rings/semirings/non_negative_integer_semiring.py +107 -0
  632. sage/rings/semirings/tropical_mpolynomial.py +972 -0
  633. sage/rings/semirings/tropical_polynomial.py +997 -0
  634. sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
  635. sage/rings/semirings/tropical_semiring.pyx +676 -0
  636. sage/rings/semirings/tropical_variety.py +1701 -0
  637. sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
  638. sage/rings/sum_of_squares.pxd +3 -0
  639. sage/rings/sum_of_squares.pyx +336 -0
  640. sage/rings/tests.py +504 -0
  641. sage/schemes/affine/affine_homset.py +508 -0
  642. sage/schemes/affine/affine_morphism.py +1574 -0
  643. sage/schemes/affine/affine_point.py +460 -0
  644. sage/schemes/affine/affine_rational_point.py +308 -0
  645. sage/schemes/affine/affine_space.py +1264 -0
  646. sage/schemes/affine/affine_subscheme.py +592 -0
  647. sage/schemes/affine/all.py +25 -0
  648. sage/schemes/all__sagemath_categories.py +5 -0
  649. sage/schemes/generic/algebraic_scheme.py +2092 -0
  650. sage/schemes/generic/all.py +5 -0
  651. sage/schemes/generic/ambient_space.py +400 -0
  652. sage/schemes/generic/divisor.py +465 -0
  653. sage/schemes/generic/divisor_group.py +313 -0
  654. sage/schemes/generic/glue.py +84 -0
  655. sage/schemes/generic/homset.py +820 -0
  656. sage/schemes/generic/hypersurface.py +234 -0
  657. sage/schemes/generic/morphism.py +2107 -0
  658. sage/schemes/generic/point.py +237 -0
  659. sage/schemes/generic/scheme.py +1190 -0
  660. sage/schemes/generic/spec.py +199 -0
  661. sage/schemes/product_projective/all.py +6 -0
  662. sage/schemes/product_projective/homset.py +236 -0
  663. sage/schemes/product_projective/morphism.py +517 -0
  664. sage/schemes/product_projective/point.py +568 -0
  665. sage/schemes/product_projective/rational_point.py +550 -0
  666. sage/schemes/product_projective/space.py +1301 -0
  667. sage/schemes/product_projective/subscheme.py +466 -0
  668. sage/schemes/projective/all.py +24 -0
  669. sage/schemes/projective/proj_bdd_height.py +453 -0
  670. sage/schemes/projective/projective_homset.py +718 -0
  671. sage/schemes/projective/projective_morphism.py +2792 -0
  672. sage/schemes/projective/projective_point.py +1484 -0
  673. sage/schemes/projective/projective_rational_point.py +569 -0
  674. sage/schemes/projective/projective_space.py +2571 -0
  675. sage/schemes/projective/projective_subscheme.py +1574 -0
  676. sage/sets/all.py +17 -0
  677. sage/sets/cartesian_product.py +376 -0
  678. sage/sets/condition_set.py +525 -0
  679. sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
  680. sage/sets/disjoint_set.pxd +36 -0
  681. sage/sets/disjoint_set.pyx +998 -0
  682. sage/sets/disjoint_union_enumerated_sets.py +625 -0
  683. sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
  684. sage/sets/family.pxd +12 -0
  685. sage/sets/family.pyx +1556 -0
  686. sage/sets/finite_enumerated_set.py +406 -0
  687. sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
  688. sage/sets/finite_set_map_cy.pxd +34 -0
  689. sage/sets/finite_set_map_cy.pyx +708 -0
  690. sage/sets/finite_set_maps.py +591 -0
  691. sage/sets/image_set.py +448 -0
  692. sage/sets/integer_range.py +829 -0
  693. sage/sets/non_negative_integers.py +241 -0
  694. sage/sets/positive_integers.py +93 -0
  695. sage/sets/primes.py +188 -0
  696. sage/sets/real_set.py +2760 -0
  697. sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
  698. sage/sets/recursively_enumerated_set.pxd +31 -0
  699. sage/sets/recursively_enumerated_set.pyx +2082 -0
  700. sage/sets/set.py +2083 -0
  701. sage/sets/set_from_iterator.py +1021 -0
  702. sage/sets/totally_ordered_finite_set.py +329 -0
  703. sage/symbolic/all__sagemath_categories.py +1 -0
  704. sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
  705. sage/symbolic/function.pxd +29 -0
  706. sage/symbolic/function.pyx +1488 -0
  707. sage/symbolic/symbols.py +56 -0
  708. sage/tests/all__sagemath_categories.py +1 -0
  709. sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
  710. sage/tests/cython.pyx +37 -0
  711. sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
  712. sage/tests/stl_vector.pyx +171 -0
  713. sage/typeset/all.py +6 -0
  714. sage/typeset/ascii_art.py +295 -0
  715. sage/typeset/character_art.py +789 -0
  716. sage/typeset/character_art_factory.py +572 -0
  717. sage/typeset/symbols.py +334 -0
  718. sage/typeset/unicode_art.py +183 -0
  719. sage/typeset/unicode_characters.py +101 -0
@@ -0,0 +1,2746 @@
1
+ # sage_setup: distribution = sagemath-categories
2
+ r"""
3
+ Fast Expression Evaluation
4
+
5
+ For many applications such as numerical integration, differential
6
+ equation approximation, plotting a 3d surface, optimization problems,
7
+ Monte-Carlo simulations, etc., one wishes to pass around and evaluate
8
+ a single algebraic expression many, many times at various floating
9
+ point values. Other applications may need to evaluate an expression
10
+ many times in interval arithmetic, or in a finite field. Doing this
11
+ via recursive calls over a python representation of the object (even
12
+ if Maxima or other outside packages are not involved) is extremely
13
+ inefficient.
14
+
15
+ This module provides a function, :func:`fast_callable`, to
16
+ transform such expressions into a form where they can be evaluated
17
+ quickly::
18
+
19
+ sage: # needs sage.symbolic
20
+ sage: f = sin(x) + 3*x^2
21
+ sage: ff = fast_callable(f, vars=[x])
22
+ sage: ff(3.5)
23
+ 36.3992167723104
24
+ sage: ff(RIF(3.5))
25
+ 36.39921677231038?
26
+
27
+ By default, :func:`fast_callable` only removes some interpretive
28
+ overhead from the evaluation, but all of the individual arithmetic
29
+ operations are done using standard Sage arithmetic. This is still a
30
+ huge win over :mod:`sage.calculus`, which evidently has a lot of overhead.
31
+ Compare the cost of evaluating Wilkinson's polynomial (in unexpanded
32
+ form) at `x = 30`::
33
+
34
+ sage: # needs sage.symbolic
35
+ sage: wilk = prod((x-i) for i in [1 .. 20]); wilk
36
+ (x - 1)*(x - 2)*(x - 3)*(x - 4)*(x - 5)*(x - 6)*(x - 7)*(x - 8)*(x - 9)*(x - 10)*(x - 11)*(x - 12)*(x - 13)*(x - 14)*(x - 15)*(x - 16)*(x - 17)*(x - 18)*(x - 19)*(x - 20)
37
+ sage: timeit('wilk.subs(x=30)') # random # long time
38
+ 625 loops, best of 3: 1.43 ms per loop
39
+ sage: fc_wilk = fast_callable(wilk, vars=[x])
40
+ sage: timeit('fc_wilk(30)') # random # long time
41
+ 625 loops, best of 3: 9.72 us per loop
42
+
43
+ You can specify a particular domain for the evaluation using
44
+ ``domain=``::
45
+
46
+ sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ) # needs sage.symbolic
47
+
48
+ The meaning of ``domain=D`` is that each intermediate and final result
49
+ is converted to type ``D``. For instance, the previous example of
50
+ ``sin(x) + 3*x^2`` with ``domain=D`` would be equivalent to
51
+ ``D(D(sin(D(x))) + D(D(3)*D(D(x)^2)))``. (This example also
52
+ demonstrates the one exception to the general rule: if an exponent is an
53
+ integral constant, then it is not wrapped with ``D()``.)
54
+
55
+ At first glance, this seems like a very bad idea if you want to
56
+ compute quickly. And it is a bad idea, for types where we don't
57
+ have a special interpreter. It's not too bad of a slowdown, though.
58
+ To mitigate the costs, we check whether the value already has
59
+ the correct parent before we call ``D``.
60
+
61
+ We don't yet have a special interpreter with domain ``ZZ``, so we can see
62
+ how that compares to the generic ``fc_wilk`` example above::
63
+
64
+ sage: timeit('fc_wilk_zz(30)') # random # long time # needs sage.symbolic
65
+ 625 loops, best of 3: 15.4 us per loop
66
+
67
+ However, for other types, using ``domain=D`` will get a large speedup,
68
+ because we have special-purpose interpreters for those types. One
69
+ example is ``RDF``. Since with ``domain=RDF`` we know that every single
70
+ operation will be floating-point, we can just execute the
71
+ floating-point operations directly and skip all the Python object
72
+ creations that you would get from actually using ``RDF`` objects::
73
+
74
+ sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF) # needs sage.symbolic
75
+ sage: timeit('fc_wilk_rdf(30.0)') # random # long time # needs sage.symbolic
76
+ 625 loops, best of 3: 7 us per loop
77
+
78
+ The domain does not need to be a Sage type; for instance, ``domain=float``
79
+ also works. (We actually use the same fast interpreter for ``domain=float``
80
+ and ``domain=RDF``; the only difference is that when ``domain=RDF`` is used,
81
+ the return value is an ``RDF`` element, and when ``domain=float`` is used,
82
+ the return value is a Python :class:`float`.) ::
83
+
84
+ sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float) # needs sage.symbolic
85
+ sage: timeit('fc_wilk_float(30.0)') # random # long time # needs sage.symbolic
86
+ 625 loops, best of 3: 5.04 us per loop
87
+
88
+ We also have support for ``RR``::
89
+
90
+ sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR) # needs sage.symbolic
91
+ sage: timeit('fc_wilk_rr(30.0)') # random # long time # needs sage.symbolic
92
+ 625 loops, best of 3: 13 us per loop
93
+
94
+ For ``CC``::
95
+
96
+ sage: fc_wilk_cc = fast_callable(wilk, vars=[x], domain=CC) # needs sage.symbolic
97
+ sage: timeit('fc_wilk_cc(30.0)') # random # long time # needs sage.symbolic
98
+ 625 loops, best of 3: 23 us per loop
99
+
100
+ And support for ``CDF``::
101
+
102
+ sage: fc_wilk_cdf = fast_callable(wilk, vars=[x], domain=CDF) # needs sage.symbolic
103
+ sage: timeit('fc_wilk_cdf(30.0)') # random # long time # needs sage.symbolic
104
+ 625 loops, best of 3: 10.2 us per loop
105
+
106
+ Currently, :func:`fast_callable` can accept two kinds of objects:
107
+ polynomials (univariate and multivariate) and symbolic expressions
108
+ (elements of the Symbolic Ring). For polynomials, you can omit the
109
+ ``vars`` argument; the variables will default to the ring generators (in
110
+ the order used when creating the ring). ::
111
+
112
+ sage: K.<x,y,z> = QQ[]
113
+ sage: p = 10*y + 100*z + x
114
+ sage: fp = fast_callable(p)
115
+ sage: fp(1,2,3)
116
+ 321
117
+
118
+ But you can also specify the variable names to override the default
119
+ ordering (you can include extra variable names here, too). ::
120
+
121
+ sage: fp = fast_callable(p, vars=('x','w','z','y'))
122
+
123
+ For symbolic expressions, you need to specify the variable names, so
124
+ that :func:`fast_callable` knows what order to use. ::
125
+
126
+ sage: # needs sage.symbolic
127
+ sage: var('y,z,x')
128
+ (y, z, x)
129
+ sage: f = 10*y + 100*z + x
130
+ sage: ff = fast_callable(f, vars=(x,y,z))
131
+ sage: ff(1,2,3)
132
+ 321
133
+
134
+ You can also specify extra variable names::
135
+
136
+ sage: ff = fast_callable(f, vars=('x','w','z','y')) # needs sage.symbolic
137
+ sage: ff(1,2,3,4) # needs sage.symbolic
138
+ 341
139
+
140
+ This should be enough for normal use of :func:`fast_callable`; let's
141
+ discuss some more advanced topics.
142
+
143
+ Sometimes it may be useful to create a fast version of an expression
144
+ without going through symbolic expressions or polynomials; perhaps
145
+ because you want to describe to :func:`fast_callable` an expression
146
+ with common subexpressions.
147
+
148
+ Internally, :func:`fast_callable` works in two stages: it constructs
149
+ an expression tree from its argument, and then it builds a
150
+ fast evaluator from that expression tree. You can bypass the first phase
151
+ by building your own expression tree and passing that directly to
152
+ :func:`fast_callable`, using an :class:`ExpressionTreeBuilder`. ::
153
+
154
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
155
+ sage: etb = ExpressionTreeBuilder(vars=('x','y','z'))
156
+
157
+ An :class:`ExpressionTreeBuilder` has three interesting methods:
158
+ :meth:`constant`, :meth:`var`, and :meth:`call`.
159
+ All of these methods return :class:`ExpressionTree` objects.
160
+
161
+ The :meth:`var` method takes a string, and returns an expression tree
162
+ for the corresponding variable. ::
163
+
164
+ sage: x = etb.var('x')
165
+ sage: y = etb.var('y')
166
+ sage: z = etb.var('y')
167
+
168
+ Expression trees support Python's numeric operators, so you can easily
169
+ build expression trees representing arithmetic expressions. ::
170
+
171
+ sage: v1 = (x+y)*(y+z) + (y//z)
172
+
173
+ The :meth:`constant` method takes a Sage value, and returns an
174
+ expression tree representing that value. ::
175
+
176
+ sage: v2 = etb.constant(3.14159) * x + etb.constant(1729) * y
177
+
178
+ The :meth:`call` method takes a sage/Python function and zero or more
179
+ expression trees, and returns an expression tree representing
180
+ the function call. ::
181
+
182
+ sage: v3 = etb.call(sin, v1+v2)
183
+ sage: v3 # needs sage.symbolic
184
+ sin(add(add(mul(add(v_0, v_1), add(v_1, v_1)), floordiv(v_1, v_1)),
185
+ add(mul(3.14159000000000, v_0), mul(1729, v_1))))
186
+
187
+ Many sage/Python built-in functions are specially handled; for instance,
188
+ when evaluating an expression involving :func:`sin` over ``RDF``,
189
+ the C math library function :func:`sin` is called. Arbitrary functions
190
+ are allowed, but will be much slower since they will call back to
191
+ Python code on every call; for example, the following will work. ::
192
+
193
+ sage: def my_sqrt(x): return pow(x, 0.5)
194
+ sage: e = etb.call(my_sqrt, v1); e
195
+ {my_sqrt}(add(mul(add(v_0, v_1), add(v_1, v_1)), floordiv(v_1, v_1)))
196
+ sage: fast_callable(e)(1, 2, 3)
197
+ 3.60555127546399
198
+
199
+ To provide :func:`fast_callable` for your own class (so that
200
+ ``fast_callable(x)`` works when ``x`` is an instance of your
201
+ class), implement a method ``_fast_callable_(self, etb)`` for your class.
202
+ This method takes an :class:`ExpressionTreeBuilder`, and returns an
203
+ expression tree built up using the methods described above.
204
+
205
+ EXAMPLES::
206
+
207
+ sage: var('x') # needs sage.symbolic
208
+ x
209
+ sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float) # needs sage.symbolic
210
+
211
+ ::
212
+
213
+ sage: f(1) # needs sage.symbolic
214
+ 1.4142135623730951
215
+ sage: f.op_list() # needs sage.symbolic
216
+ [('load_arg', 0), ('ipow', 7), ('load_const', 1.0), 'add', 'sqrt', 'return']
217
+
218
+ To interpret that last line, we load argument 0 (``x`` in this case) onto
219
+ the stack, push the constant `7.0` onto the stack, call the :func:`pow`
220
+ functionn(which takes 2 arguments from the stack), push the constant `1.0`,
221
+ add the top two arguments of the stack, and then call :func:`sqrt`.
222
+
223
+ Here we take :func:`sin` of the first argument and add it to ``f``::
224
+
225
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
226
+ sage: etb = ExpressionTreeBuilder('x')
227
+ sage: x = etb.var('x')
228
+ sage: f = etb.call(sqrt, x^7 + 1)
229
+ sage: g = etb.call(sin, x)
230
+ sage: fast_callable(f+g).op_list()
231
+ [('load_arg', 0), ('ipow', 7), ('load_const', 1), 'add',
232
+ ('py_call', <function sqrt at ...>, 1), ('load_arg', 0), ('py_call', sin, 1),
233
+ 'add', 'return']
234
+
235
+
236
+ AUTHOR:
237
+
238
+ - Carl Witty (2009-02): initial version (heavily inspired by
239
+ Robert Bradshaw's fast_eval.pyx)
240
+
241
+ .. TODO::
242
+
243
+ The following bits of text were written for the module docstring.
244
+ They are not true yet, but I hope they will be true someday, at
245
+ which point I will move them into the main text.
246
+
247
+ The final interesting method of :class:`ExpressionTreeBuilder` is
248
+ :meth:`choice`. This produces conditional expressions, like the C
249
+ ``COND ? T : F`` expression or the Python ``T if COND else F``.
250
+ This lets you define piecewise functions using :func:`fast_callable`. ::
251
+
252
+ sage: v4 = etb.choice(v3 >= etb.constant(0), v1, v2) # not tested
253
+
254
+ The arguments are ``(COND, T, F)`` (the same order as in C), so the
255
+ above means that if ``v3`` evaluates to a nonnegative number,
256
+ then ``v4`` will evaluate to the result of ``v1``;
257
+ otherwise, ``v4`` will evaluate to the result of ``v2``.
258
+
259
+ Let's see an example where we see that :func:`fast_callable` does not
260
+ evaluate common subexpressions more than once. We'll make a
261
+ :func:`fast_callable` expression that gives the result
262
+ of 16 iterations of the Mandelbrot function. ::
263
+
264
+ sage: etb = ExpressionTreeBuilder('c')
265
+ sage: z = etb.constant(0)
266
+ sage: c = etb.var('c')
267
+ sage: for i in range(16):
268
+ ....: z = z*z + c
269
+ sage: mand = fast_callable(z, domain=CDF) # needs sage.rings.complex_double
270
+
271
+ Now ``ff`` does 32 complex arithmetic operations on each call
272
+ (16 additions and 16 multiplications). However, if ``z*z`` produced
273
+ code that evaluated ``z`` twice, then this would do many
274
+ thousands of arithmetic operations instead.
275
+
276
+ Note that the handling for common subexpressions only checks whether
277
+ expression trees are the same Python object; for instance, the following
278
+ code will evaluate ``x+1`` twice::
279
+
280
+ sage: etb = ExpressionTreeBuilder('x')
281
+ sage: x = etb.var('x')
282
+ sage: (x+1)*(x+1)
283
+ mul(add(v_0, 1), add(v_0, 1))
284
+
285
+ but this code will only evaluate ``x+1`` once::
286
+
287
+ sage: v = x+1; v*v
288
+ mul(add(v_0, 1), add(v_0, 1))
289
+ """
290
+
291
+
292
+ #*****************************************************************************
293
+ # Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu>
294
+ # Copyright (C) 2009 Carl Witty <Carl.Witty@gmail.com>
295
+ #
296
+ # Distributed under the terms of the GNU General Public License (GPL)
297
+ #
298
+ # This code is distributed in the hope that it will be useful,
299
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
300
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
301
+ # General Public License for more details.
302
+ #
303
+ # The full text of the GPL is available at:
304
+ #
305
+ # http://www.gnu.org/licenses/
306
+ #*****************************************************************************
307
+
308
+ import operator
309
+ from copy import copy
310
+ from math import isnan, nan
311
+
312
+ import sage.rings.abc
313
+ from sage.rings.integer import Integer
314
+ from sage.rings.integer_ring import ZZ
315
+ from sage.structure.element cimport parent
316
+ from sage.structure.element cimport Expression as Expression_abc
317
+
318
+
319
+ def fast_callable(x, domain=None, vars=None,
320
+ expect_one_var=False):
321
+ r"""
322
+ Given an expression ``x``, compile it into a form that can be quickly
323
+ evaluated, given values for the variables in ``x``.
324
+
325
+ Currently, ``x`` can be an expression object, an element of ``SR``, or a
326
+ (univariate or multivariate) polynomial; this list will probably
327
+ be extended soon.
328
+
329
+ By default, ``x`` is evaluated the same way that a Python function
330
+ would evaluate it -- addition maps to ``PyNumber_Add``, etc. However,
331
+ you can specify ``domain=D`` where ``D`` is some Sage parent or Python
332
+ type; in this case, all arithmetic is done in that domain. If we
333
+ have a special-purpose interpreter for that parent (like ``RDF`` or
334
+ :class:`float`), ``domain=...`` will trigger the use of that interpreter.
335
+
336
+ If ``vars`` is ``None`` and ``x`` is a polynomial, then we will use the
337
+ generators of ``parent(x)`` as the variables; otherwise, ``vars`` must be
338
+ specified (unless ``x`` is a symbolic expression with only one variable,
339
+ and ``expect_one_var`` is ``True``, in which case we will use that variable).
340
+
341
+ EXAMPLES::
342
+
343
+ sage: # needs sage.symbolic
344
+ sage: var('x')
345
+ x
346
+ sage: expr = sin(x) + 3*x^2
347
+ sage: f = fast_callable(expr, vars=[x])
348
+ sage: f(2)
349
+ sin(2) + 12
350
+ sage: f(2.0)
351
+ 12.9092974268257
352
+
353
+ We have special fast interpreters for ``domain=float`` and ``domain=RDF``.
354
+ (Actually it's the same interpreter; only the return type varies.)
355
+ Note that the float interpreter is not actually more accurate than
356
+ the ``RDF`` interpreter; elements of ``RDF`` just don't display all
357
+ their digits. We have special fast interpreter for ``domain=CDF``::
358
+
359
+ sage: # needs sage.symbolic
360
+ sage: f_float = fast_callable(expr, vars=[x], domain=float)
361
+ sage: f_float(2)
362
+ 12.909297426825681
363
+ sage: f_rdf = fast_callable(expr, vars=[x], domain=RDF)
364
+ sage: f_rdf(2)
365
+ 12.909297426825681
366
+ sage: f_cdf = fast_callable(expr, vars=[x], domain=CDF)
367
+ sage: f_cdf(2)
368
+ 12.909297426825681
369
+ sage: f_cdf(2+I)
370
+ 10.40311925062204 + 11.510943740958707*I
371
+ sage: f = fast_callable(expr, vars=('z','x','y'))
372
+ sage: f(1, 2, 3)
373
+ sin(2) + 12
374
+
375
+ sage: K.<x> = QQ[]
376
+ sage: p = -1/4*x^6 + 1/2*x^5 - x^4 - 12*x^3 + 1/2*x^2 - 1/95*x - 1/2
377
+ sage: fp = fast_callable(p, domain=RDF)
378
+ sage: fp.op_list()
379
+ [('load_arg', 0), ('load_const', -0.25), 'mul', ('load_const', 0.5), 'add',
380
+ ('load_arg', 0), 'mul', ('load_const', -1.0), 'add', ('load_arg', 0), 'mul',
381
+ ('load_const', -12.0), 'add', ('load_arg', 0), 'mul', ('load_const', 0.5),
382
+ 'add', ('load_arg', 0), 'mul', ('load_const', -0.010526315789473684),
383
+ 'add', ('load_arg', 0), 'mul', ('load_const', -0.5), 'add', 'return']
384
+ sage: fp(3.14159)
385
+ -552.4182988917153
386
+
387
+ sage: K.<x,y,z> = QQ[]
388
+ sage: p = x*y^2 + 1/3*y^2 - x*z - y*z
389
+ sage: fp = fast_callable(p, domain=RDF)
390
+ sage: fp.op_list()
391
+ [('load_const', 0.0), ('load_const', 1.0), ('load_arg', 0), ('ipow', 1),
392
+ ('load_arg', 1), ('ipow', 2), 'mul', 'mul', 'add',
393
+ ('load_const', 0.3333333333333333), ('load_arg', 1), ('ipow', 2), 'mul', 'add',
394
+ ('load_const', -1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 2),
395
+ ('ipow', 1), 'mul', 'mul', 'add', ('load_const', -1.0), ('load_arg', 1),
396
+ ('ipow', 1), ('load_arg', 2), ('ipow', 1), 'mul', 'mul', 'add', 'return']
397
+ sage: fp(e, pi, sqrt(2)) # abs tol 3e-14 # needs sage.symbolic
398
+ 21.831120464939584
399
+ sage: symbolic_result = p(e, pi, sqrt(2)); symbolic_result # needs sage.symbolic
400
+ pi^2*e + 1/3*pi^2 - sqrt(2)*pi - sqrt(2)*e
401
+ sage: n(symbolic_result) # needs sage.symbolic
402
+ 21.8311204649396
403
+
404
+ ::
405
+
406
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
407
+ sage: etb = ExpressionTreeBuilder(vars=('x','y'), domain=float)
408
+ sage: x = etb.var('x')
409
+ sage: y = etb.var('y')
410
+ sage: expr = etb.call(sin, x^2 + y); expr
411
+ sin(add(ipow(v_0, 2), v_1))
412
+ sage: fc = fast_callable(expr, domain=float)
413
+ sage: fc(5, 7)
414
+ 0.5514266812416906
415
+
416
+ Check that :func:`fast_callable` also works for symbolic functions with
417
+ evaluation functions::
418
+
419
+ sage: # needs sage.symbolic
420
+ sage: def evalf_func(self, x, y, parent):
421
+ ....: return parent(x*y) if parent is not None else x*y
422
+ sage: x,y = var('x,y')
423
+ sage: f = function('f', evalf_func=evalf_func)
424
+ sage: fc = fast_callable(f(x, y), vars=[x, y])
425
+ sage: fc(3, 4)
426
+ f(3, 4)
427
+
428
+ And also when there are complex values involved::
429
+
430
+ sage: # needs sage.symbolic
431
+ sage: def evalf_func(self, x, y, parent):
432
+ ....: return parent(I*x*y) if parent is not None else I*x*y
433
+ sage: g = function('g', evalf_func=evalf_func)
434
+ sage: fc = fast_callable(g(x, y), vars=[x, y])
435
+ sage: fc(3, 4)
436
+ g(3, 4)
437
+ sage: fc2 = fast_callable(g(x, y), domain=complex, vars=[x, y])
438
+ sage: fc2(3, 4)
439
+ 12j
440
+ sage: fc3 = fast_callable(g(x, y), domain=float, vars=[x, y])
441
+ sage: fc3(3, 4)
442
+ Traceback (most recent call last):
443
+ ...
444
+ TypeError: unable to simplify to float approximation
445
+ """
446
+ cdef Expression et
447
+ if isinstance(x, Expression):
448
+ et = x
449
+ vars = et._etb._vars
450
+ else:
451
+ if not vars:
452
+ # fast_float passes empty list/tuple
453
+ vars = None
454
+
455
+ if isinstance(x, Expression_abc) and x.is_callable():
456
+ if vars is None:
457
+ vars = x.arguments()
458
+ if expect_one_var and len(vars) != 1:
459
+ raise ValueError(f"passed expect_one_var=True, but the callable expression takes {len(vars)} arguments")
460
+ elif isinstance(x, Expression_abc):
461
+ if vars is None:
462
+ vars = x.variables()
463
+ if expect_one_var and len(vars) <= 1:
464
+ if not vars:
465
+ vars = ['EXTRA_VAR0']
466
+ else:
467
+ raise ValueError("list of variables must be specified for symbolic expressions")
468
+
469
+ def to_var(var):
470
+ if isinstance(var, Expression_abc) and var.is_symbol():
471
+ return var
472
+ from sage.symbolic.ring import SR
473
+ return SR.var(var)
474
+ vars = [to_var(var) for var in vars]
475
+ # Convert to a callable symbolic expression
476
+ x = x.function(*vars)
477
+
478
+ if vars is None:
479
+ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic
480
+ from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
481
+ P = x.parent()
482
+ if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)):
483
+ vars = P.variable_names()
484
+ else:
485
+ # constant
486
+ vars = ()
487
+
488
+ etb = ExpressionTreeBuilder(vars=vars, domain=domain)
489
+ et = x._fast_callable_(etb)
490
+
491
+ builder, str = _builder_and_stream(vars=vars, domain=domain)
492
+
493
+ generate_code(et, str)
494
+ str.instr('return')
495
+ return builder(str.get_current())
496
+
497
+
498
+ def _builder_and_stream(vars, domain):
499
+ r"""
500
+ Return a builder and a stream.
501
+
502
+ This is an internal function used only once, by :func:`fast_callable`.
503
+
504
+ INPUT:
505
+
506
+ - ``vars`` -- a sequence of variable names
507
+
508
+ - ``domain`` -- a Sage parent or Python type or ``None``; if non-``None``,
509
+ all arithmetic is done in that domain
510
+
511
+ OUTPUT: a :class:`Wrapper`, an class:`InstructionStream`
512
+
513
+ EXAMPLES::
514
+
515
+ sage: from sage.ext.fast_callable import _builder_and_stream
516
+ sage: _builder_and_stream(["x", "y"], ZZ)
517
+ (<class '...interpreters.wrapper_el.Wrapper_el'>,
518
+ <sage.ext.fast_callable.InstructionStream object at 0x...>)
519
+ sage: _builder_and_stream(["x", "y"], RR) # needs sage.rings.real_mpfr
520
+ (<class '...interpreters.wrapper_rr.Wrapper_rr'>,
521
+ <sage.ext.fast_callable.InstructionStream object at 0x...>)
522
+
523
+ Modularized test with sagemath-categories after :issue:`35095`, which has
524
+ (a basic version of) ``RDF`` but not the specialized interpreter for it.
525
+ In this case, the function falls back to using the :class:`Element`
526
+ interpreter::
527
+
528
+ sage: domain = RDF
529
+ sage: from sage.structure.element import Element as domain
530
+ sage: _builder_and_stream(["x", "y"], domain)
531
+ (<class '...interpreters.wrapper_el.Wrapper_el'>,
532
+ <sage.ext.fast_callable.InstructionStream object at 0x...>)
533
+ """
534
+ if isinstance(domain, sage.rings.abc.RealField):
535
+ try:
536
+ from sage.ext.interpreters.wrapper_rr import metadata, Wrapper_rr as builder
537
+ except ImportError:
538
+ pass
539
+ else:
540
+ return builder, InstructionStream(metadata, len(vars), domain)
541
+
542
+ if isinstance(domain, sage.rings.abc.ComplexField):
543
+ try:
544
+ from sage.ext.interpreters.wrapper_cc import metadata, Wrapper_cc as builder
545
+ except ImportError:
546
+ pass
547
+ else:
548
+ return builder, InstructionStream(metadata, len(vars), domain)
549
+
550
+ if isinstance(domain, sage.rings.abc.RealDoubleField) or domain is float:
551
+ try:
552
+ from sage.ext.interpreters.wrapper_rdf import metadata, Wrapper_rdf as builder
553
+ except ImportError:
554
+ pass
555
+ else:
556
+ return builder, InstructionStream(metadata, len(vars), domain)
557
+
558
+ if isinstance(domain, sage.rings.abc.ComplexDoubleField):
559
+ try:
560
+ from sage.ext.interpreters.wrapper_cdf import metadata, Wrapper_cdf as builder
561
+ except ImportError:
562
+ pass
563
+ else:
564
+ return builder, InstructionStream(metadata, len(vars), domain)
565
+
566
+ if domain is None:
567
+ from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py as builder
568
+ return builder, InstructionStream(metadata, len(vars))
569
+
570
+ from sage.ext.interpreters.wrapper_el import metadata, Wrapper_el as builder
571
+ return builder, InstructionStream(metadata, len(vars), domain)
572
+
573
+
574
+ def function_name(fn):
575
+ r"""
576
+ Given a function, return a string giving a name for the function.
577
+
578
+ For functions we recognize, we use our standard opcode name for the
579
+ function (so :func:`operator.add` becomes ``'add'``, and
580
+ :func:`sage.functions.trig.sin` becomes ``'sin'``).
581
+
582
+ For functions we don't recognize, we try to come up with a name,
583
+ but the name will be wrapped in braces; this is a signal that
584
+ we'll definitely use a slow Python call to call this function.
585
+ (We may use a slow Python call even for functions we do recognize,
586
+ if we're targeting an interpreter without an opcode for the function.)
587
+
588
+ Only used when printing Expressions.
589
+
590
+ EXAMPLES::
591
+
592
+ sage: from sage.ext.fast_callable import function_name
593
+ sage: function_name(operator.pow)
594
+ 'pow'
595
+ sage: function_name(cos) # needs sage.symbolic
596
+ 'cos'
597
+ sage: function_name(factorial)
598
+ '{factorial}'
599
+ """
600
+ from sage.structure.dynamic_class import DynamicMetaclass
601
+ if isinstance(type(fn), DynamicMetaclass):
602
+ return "{%r}" % fn
603
+ builtins = get_builtin_functions()
604
+ if fn in builtins:
605
+ return builtins[fn]
606
+ try:
607
+ return "{%s}" % fn.__name__
608
+ except AttributeError:
609
+ return "{%r}" % fn
610
+
611
+
612
+ cdef class ExpressionTreeBuilder:
613
+ r"""
614
+ A class with helper methods for building Expressions.
615
+
616
+ An instance of this class is passed to :meth:`_fast_callable_` methods;
617
+ you can also instantiate it yourself to create your own expressions
618
+ for :func:`fast_callable`, bypassing :meth:`_fast_callable_`.
619
+
620
+ EXAMPLES::
621
+
622
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
623
+ sage: etb = ExpressionTreeBuilder('x')
624
+ sage: x = etb.var('x')
625
+ sage: (x+3)*5
626
+ mul(add(v_0, 3), 5)
627
+ """
628
+
629
+ cdef readonly object _domain
630
+ cdef readonly object _vars
631
+
632
+ def __init__(self, vars, domain=None):
633
+ r"""
634
+ Initialize an instance of :class:`ExpressionTreeBuilder`.
635
+
636
+ Takes a list or tuple of variable names to use, and also an optional
637
+ ``domain``. If a ``domain`` is given, then creating an
638
+ :class:`ExpressionConstant` node with the :meth:`__call__`, make, or
639
+ constant methods will convert the value into the given domain.
640
+
641
+ Note that this is the only effect of the domain parameter. It
642
+ is quite possible to use different domains for
643
+ :class:`ExpressionTreeBuilder` and for :func:`fast_callable`; in that case,
644
+ constants will be converted twice (once when building the
645
+ :class:`Expression`, and once when generating code).
646
+
647
+ EXAMPLES::
648
+
649
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
650
+ sage: etb = ExpressionTreeBuilder('x')
651
+ sage: etb(3^50)
652
+ 717897987691852588770249
653
+ sage: etb = ExpressionTreeBuilder('x', domain=RR)
654
+ sage: etb(3^50)
655
+ 7.17897987691853e23
656
+ """
657
+
658
+ if isinstance(vars, tuple):
659
+ vars = list(vars)
660
+ elif not isinstance(vars, list):
661
+ vars = [vars]
662
+
663
+ vars = [self._clean_var(v) for v in vars]
664
+
665
+ self._domain = domain
666
+ self._vars = vars
667
+
668
+ def __call__(self, x):
669
+ r"""
670
+ Try to convert the given value to an :class:`Expression`.
671
+
672
+ If it is already an Expression, just return it. If it has a
673
+ :meth:`_fast_callable_` method, then call the method with ``self`` as
674
+ an argument. Otherwise, use ``self.constant()`` to turn it into a constant.
675
+
676
+ EXAMPLES::
677
+
678
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
679
+ sage: etb = ExpressionTreeBuilder('x')
680
+ sage: v = etb(3); v, type(v)
681
+ (3, <class 'sage.ext.fast_callable.ExpressionConstant'>)
682
+ sage: v = etb(polygen(QQ)); v, type(v)
683
+ (v_0, <class 'sage.ext.fast_callable.ExpressionVariable'>)
684
+ sage: v is etb(v)
685
+ True
686
+ """
687
+ if isinstance(x, Expression):
688
+ return x
689
+
690
+ try:
691
+ fc = x._fast_callable_
692
+ except AttributeError:
693
+ return self.constant(x)
694
+
695
+ return fc(self)
696
+
697
+ def _clean_var(self, v):
698
+ r"""
699
+ Give a variable name, given a variable.
700
+
701
+ EXAMPLES::
702
+
703
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
704
+ sage: etb = ExpressionTreeBuilder('x')
705
+ sage: var('x') # needs sage.symbolic
706
+ x
707
+ sage: etb._clean_var(x) # needs sage.symbolic
708
+ 'x'
709
+ sage: x = polygen(RR); x
710
+ x
711
+ sage: etb._clean_var(x)
712
+ 'x'
713
+ """
714
+ # There should be a better way to do this. (Maybe there is.)
715
+ if not isinstance(v, str):
716
+ v = str(v)
717
+ if '*' in v:
718
+ v = v[v.index('*')+1:]
719
+ return v
720
+
721
+ def constant(self, c):
722
+ r"""
723
+ Turn the argument into an :class:`ExpressionConstant`, converting it to
724
+ our domain if we have one.
725
+
726
+ EXAMPLES::
727
+
728
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
729
+ sage: etb = ExpressionTreeBuilder('x')
730
+ sage: etb.constant(pi) # needs sage.symbolic
731
+ pi
732
+ sage: etb = ExpressionTreeBuilder('x', domain=RealField(200)) # needs sage.rings.real_mpfr
733
+ sage: etb.constant(pi) # needs sage.rings.real_mpfr sage.symbolic
734
+ 3.1415926535897932384626433832795028841971693993751058209749
735
+ """
736
+ if self._domain is not None:
737
+ c = self._domain(c)
738
+ return ExpressionConstant(self, c)
739
+
740
+ def var(self, v):
741
+ r"""
742
+ Turn the argument into an :class:`ExpressionVariable`. Look it up in
743
+ the list of variables. (Variables are matched by name.)
744
+
745
+ EXAMPLES::
746
+
747
+ sage: # needs sage.symbolic
748
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
749
+ sage: var('a,b,some_really_long_name')
750
+ (a, b, some_really_long_name)
751
+ sage: x = polygen(QQ)
752
+ sage: etb = ExpressionTreeBuilder(vars=('a','b',some_really_long_name, x))
753
+ sage: etb.var(some_really_long_name)
754
+ v_2
755
+ sage: etb.var('some_really_long_name')
756
+ v_2
757
+ sage: etb.var(x)
758
+ v_3
759
+ sage: etb.var('y')
760
+ Traceback (most recent call last):
761
+ ...
762
+ ValueError: Variable 'y' not found...
763
+ """
764
+ var_name = self._clean_var(v)
765
+ try:
766
+ ind = self._vars.index(var_name)
767
+ except ValueError:
768
+ raise ValueError(f"Variable '{var_name}' not found in {self._vars}")
769
+ return ExpressionVariable(self, ind)
770
+
771
+ def _var_number(self, n):
772
+ r"""
773
+ Given an integer, return the variable with that index.
774
+
775
+ EXAMPLES::
776
+
777
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
778
+ sage: etb = ExpressionTreeBuilder(vars=('a','b','c','d'))
779
+ sage: etb._var_number(0)
780
+ v_0
781
+ sage: etb._var_number(3)
782
+ v_3
783
+ sage: etb._var_number(4)
784
+ Traceback (most recent call last):
785
+ ...
786
+ ValueError: Variable number 4 out of range
787
+ """
788
+ if 0 <= n < len(self._vars):
789
+ return ExpressionVariable(self, n)
790
+ raise ValueError("Variable number %d out of range" % n)
791
+
792
+ def call(self, fn, *args):
793
+ r"""
794
+ Construct a call node, given a function and a list of arguments.
795
+
796
+ The arguments will be converted to Expressions using
797
+ :meth:`ExpressionTreeBuilder.__call__`.
798
+
799
+ As a special case, notice if the function is :func:`operator.pow` and
800
+ the second argument is integral, and construct an :class:`ExpressionIPow`
801
+ instead.
802
+
803
+ EXAMPLES::
804
+
805
+ sage: # needs sage.symbolic
806
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
807
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
808
+ sage: etb.call(cos, x)
809
+ cos(v_0)
810
+ sage: etb.call(sin, 1)
811
+ sin(1)
812
+ sage: etb.call(sin, etb(1))
813
+ sin(1)
814
+ sage: etb.call(factorial, x+57)
815
+ {factorial}(add(v_0, 57))
816
+ sage: etb.call(operator.pow, x, 543)
817
+ ipow(v_0, 543)
818
+ """
819
+ if fn is operator.pow:
820
+ base, exponent = args
821
+ return self(base)**exponent
822
+ else:
823
+ return ExpressionCall(self, fn, [self(a) for a in args])
824
+
825
+ def choice(self, cond, iftrue, iffalse):
826
+ r"""
827
+ Construct a choice node (a conditional expression), given the
828
+ condition, and the values for the true and false cases.
829
+
830
+ (It's possible to create choice nodes, but they don't work yet.)
831
+
832
+ EXAMPLES::
833
+
834
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
835
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
836
+ sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) # needs sage.symbolic
837
+ (0 if {eq}(v_0, 0) else div(1, v_0))
838
+ """
839
+ return ExpressionChoice(self,
840
+ cond,
841
+ self(iftrue),
842
+ self(iffalse))
843
+
844
+
845
+ # Cache these values, to make expression building a tiny bit faster
846
+ # (by skipping the hash-table lookup in the operator module).
847
+ cdef op_add = operator.add
848
+ cdef op_sub = operator.sub
849
+ cdef op_mul = operator.mul
850
+ cdef op_div
851
+ try:
852
+ op_div = operator.div
853
+ except AttributeError:
854
+ op_div = object() # Unique object not equal to anything else
855
+ cdef op_truediv = operator.truediv
856
+ cdef op_floordiv = operator.floordiv
857
+ cdef op_pow = operator.pow
858
+ cdef op_neg = operator.neg
859
+ cdef op_abs = operator.abs
860
+ cdef op_inv = operator.inv
861
+
862
+
863
+ cdef class Expression:
864
+ r"""
865
+ Represent an expression for :func:`fast_callable`.
866
+
867
+ Supports the standard Python arithmetic operators; if arithmetic
868
+ is attempted between an Expression and a non-Expression, the
869
+ non-Expression is converted to an expression (using the
870
+ :meth:`__call__` method of the Expression's :class:`ExpressionTreeBuilder`).
871
+
872
+ EXAMPLES::
873
+
874
+ sage: # needs sage.symbolic
875
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
876
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
877
+ sage: x = etb.var(x)
878
+ sage: etb(x)
879
+ v_0
880
+ sage: etb(3)
881
+ 3
882
+ sage: etb.call(sin, x)
883
+ sin(v_0)
884
+ sage: (x+1)/(x-1)
885
+ div(add(v_0, 1), sub(v_0, 1))
886
+ sage: x//5
887
+ floordiv(v_0, 5)
888
+ sage: -abs(~x)
889
+ neg(abs(inv(v_0)))
890
+ """
891
+
892
+ cdef ExpressionTreeBuilder _etb
893
+
894
+ def __init__(self, etb):
895
+ r"""
896
+ Initialize an Expression. Sets the _etb member.
897
+
898
+ EXAMPLES::
899
+
900
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
901
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
902
+ sage: v = etb(3); v # indirect doctest # needs sage.symbolic
903
+ 3
904
+ sage: v._get_etb() is etb # needs sage.symbolic
905
+ True
906
+ """
907
+ self._etb = etb
908
+
909
+ def _get_etb(self):
910
+ r"""
911
+ Return the ExpressionTreeBuilder used to build a given expression.
912
+
913
+ EXAMPLES::
914
+
915
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
916
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
917
+ sage: v = etb(3); v # needs sage.symbolic
918
+ 3
919
+ sage: v._get_etb() is etb # needs sage.symbolic
920
+ True
921
+ """
922
+ return self._etb
923
+
924
+ def __add__(s, o):
925
+ r"""
926
+ Compute a sum of two Expressions.
927
+
928
+ EXAMPLES::
929
+
930
+ sage: # needs sage.symbolic
931
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
932
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
933
+ sage: x = etb(x)
934
+ sage: x+x
935
+ add(v_0, v_0)
936
+ sage: x+1
937
+ add(v_0, 1)
938
+ sage: 1+x
939
+ add(1, v_0)
940
+ sage: x.__add__(1)
941
+ add(v_0, 1)
942
+ sage: x.__radd__(1)
943
+ add(1, v_0)
944
+ """
945
+ return _expression_binop_helper(s, o, op_add)
946
+
947
+ def __sub__(s, o):
948
+ r"""
949
+ Compute a difference of two Expressions.
950
+
951
+ EXAMPLES::
952
+
953
+ sage: # needs sage.symbolic
954
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
955
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
956
+ sage: x = etb(x)
957
+ sage: x-x
958
+ sub(v_0, v_0)
959
+ sage: x-1
960
+ sub(v_0, 1)
961
+ sage: 1-x
962
+ sub(1, v_0)
963
+ sage: x.__sub__(1)
964
+ sub(v_0, 1)
965
+ sage: x.__rsub__(1)
966
+ sub(1, v_0)
967
+ """
968
+ return _expression_binop_helper(s, o, op_sub)
969
+
970
+ def __mul__(s, o):
971
+ r"""
972
+ Compute a product of two Expressions.
973
+
974
+ EXAMPLES::
975
+
976
+ sage: # needs sage.symbolic
977
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
978
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
979
+ sage: x = etb(x)
980
+ sage: x*x
981
+ mul(v_0, v_0)
982
+ sage: x*1
983
+ mul(v_0, 1)
984
+ sage: 1*x
985
+ mul(1, v_0)
986
+ sage: x.__mul__(1)
987
+ mul(v_0, 1)
988
+ sage: x.__rmul__(1)
989
+ mul(1, v_0)
990
+ """
991
+ return _expression_binop_helper(s, o, op_mul)
992
+
993
+ def __truediv__(s, o):
994
+ r"""
995
+ Compute a quotient of two Expressions.
996
+
997
+ EXAMPLES::
998
+
999
+ sage: # needs sage.symbolic
1000
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1001
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1002
+ sage: x = etb(x)
1003
+ sage: x/x
1004
+ div(v_0, v_0)
1005
+ sage: x/1
1006
+ div(v_0, 1)
1007
+ sage: 1/x
1008
+ div(1, v_0)
1009
+ sage: x.__truediv__(1)
1010
+ div(v_0, 1)
1011
+ sage: x.__rtruediv__(1)
1012
+ div(1, v_0)
1013
+ """
1014
+ return _expression_binop_helper(s, o, op_truediv)
1015
+
1016
+ def __floordiv__(s, o):
1017
+ r"""
1018
+ Compute the floordiv (the floor of the quotient) of two Expressions.
1019
+
1020
+ EXAMPLES::
1021
+
1022
+ sage: # needs sage.symbolic
1023
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1024
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1025
+ sage: x = etb(x)
1026
+ sage: x//x
1027
+ floordiv(v_0, v_0)
1028
+ sage: x//1
1029
+ floordiv(v_0, 1)
1030
+ sage: 1//x
1031
+ floordiv(1, v_0)
1032
+ sage: x.__floordiv__(1)
1033
+ floordiv(v_0, 1)
1034
+ sage: x.__rfloordiv__(1)
1035
+ floordiv(1, v_0)
1036
+ """
1037
+ return _expression_binop_helper(s, o, op_floordiv)
1038
+
1039
+ def __pow__(s, o, dummy):
1040
+ r"""
1041
+ Compute a power expression from two Expressions.
1042
+
1043
+ If the second Expression is a constant integer, then return
1044
+ an :class:`ExpressionIPow` instead of an :class:`ExpressionCall`.
1045
+
1046
+ EXAMPLES::
1047
+
1048
+ sage: # needs sage.symbolic
1049
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1050
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1051
+ sage: x = etb(x)
1052
+ sage: x^x
1053
+ pow(v_0, v_0)
1054
+ sage: x^1
1055
+ ipow(v_0, 1)
1056
+ sage: x.__pow__(1)
1057
+ ipow(v_0, 1)
1058
+ sage: x.__pow__(1.0)
1059
+ pow(v_0, 1.00000000000000)
1060
+ sage: x.__rpow__(1)
1061
+ pow(1, v_0)
1062
+ """
1063
+ # XXX There is a performance regression from the original
1064
+ # fast_float here; it would replace small integer powers with
1065
+ # multiplication. We can't do this safely until we support
1066
+ # common subexpression elimination (or at least the dup instruction).
1067
+ # (Plus, we should consider how strict a semantics we want;
1068
+ # probably this sort of optimization should be controlled by a
1069
+ # flag.)
1070
+
1071
+ cdef Expression es
1072
+ if isinstance(o, (int, Integer)):
1073
+ es = s
1074
+ return ExpressionIPow(es._etb, s, o)
1075
+ else:
1076
+ # I really don't like this, but I can't think of a better way
1077
+ if isinstance(o, Expression_abc) and o in ZZ:
1078
+ es = s
1079
+ return ExpressionIPow(es._etb, s, ZZ(o))
1080
+ else:
1081
+ return _expression_binop_helper(s, o, op_pow)
1082
+
1083
+ def __neg__(self):
1084
+ r"""
1085
+ Compute the negation of an Expression.
1086
+
1087
+ EXAMPLES::
1088
+
1089
+ sage: # needs sage.symbolic
1090
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1091
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1092
+ sage: x = etb(x)
1093
+ sage: -x
1094
+ neg(v_0)
1095
+ sage: x.__neg__()
1096
+ neg(v_0)
1097
+ """
1098
+ return ExpressionCall(self._etb, op_neg, [self])
1099
+
1100
+ def __abs__(self):
1101
+ r"""
1102
+ Compute the absolute value of an Expression.
1103
+
1104
+ EXAMPLES::
1105
+
1106
+ sage: # needs sage.symbolic
1107
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1108
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1109
+ sage: x = etb(x)
1110
+ sage: abs(x)
1111
+ abs(v_0)
1112
+ sage: x.abs()
1113
+ abs(v_0)
1114
+ sage: x.__abs__()
1115
+ abs(v_0)
1116
+ """
1117
+ return ExpressionCall(self._etb, op_abs, [self])
1118
+
1119
+ def abs(self):
1120
+ r"""
1121
+ Compute the absolute value of an Expression.
1122
+
1123
+ EXAMPLES::
1124
+
1125
+ sage: # needs sage.symbolic
1126
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1127
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1128
+ sage: x = etb(x)
1129
+ sage: abs(x)
1130
+ abs(v_0)
1131
+ sage: x.abs()
1132
+ abs(v_0)
1133
+ sage: x.__abs__()
1134
+ abs(v_0)
1135
+ """
1136
+ return ExpressionCall(self._etb, op_abs, [self])
1137
+
1138
+ def __invert__(self):
1139
+ r"""
1140
+ Compute the inverse of an Expression.
1141
+
1142
+ EXAMPLES::
1143
+
1144
+ sage: # needs sage.symbolic
1145
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1146
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1147
+ sage: x = etb(x)
1148
+ sage: ~x
1149
+ inv(v_0)
1150
+ sage: x.__invert__()
1151
+ inv(v_0)
1152
+ """
1153
+ return ExpressionCall(self._etb, op_inv, [self])
1154
+
1155
+
1156
+ cdef class ExpressionConstant(Expression):
1157
+ r"""
1158
+ An Expression that represents an arbitrary constant.
1159
+
1160
+ EXAMPLES::
1161
+
1162
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1163
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1164
+ sage: type(etb(3)) # needs sage.symbolic
1165
+ <class 'sage.ext.fast_callable.ExpressionConstant'>
1166
+ """
1167
+
1168
+ cdef object _value
1169
+
1170
+ def __init__(self, etb, c):
1171
+ r"""
1172
+ Initialize an :class:`ExpressionConstant`.
1173
+
1174
+ EXAMPLES::
1175
+
1176
+ sage: # needs sage.symbolic
1177
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionConstant
1178
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1179
+ sage: etb(3)
1180
+ 3
1181
+ sage: v = ExpressionConstant(etb, 3); v
1182
+ 3
1183
+ sage: v._get_etb() is etb
1184
+ True
1185
+ sage: v.value()
1186
+ 3
1187
+ sage: v.value() == 3
1188
+ True
1189
+ """
1190
+ Expression.__init__(self, etb)
1191
+ self._value = c
1192
+
1193
+ def value(self):
1194
+ r"""
1195
+ Return the constant value of an :class:`ExpressionConstant`.
1196
+
1197
+ EXAMPLES::
1198
+
1199
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1200
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1201
+ sage: etb(3).value() # needs sage.symbolic
1202
+ 3
1203
+ """
1204
+ return self._value
1205
+
1206
+ def __repr__(self):
1207
+ r"""
1208
+ Give a string representing this :class:`ExpressionConstant`.
1209
+ (We use the repr of its value.)
1210
+
1211
+ EXAMPLES::
1212
+
1213
+ sage: # needs sage.symbolic
1214
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1215
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1216
+ sage: v = etb.constant(pi)
1217
+ sage: v
1218
+ pi
1219
+ sage: repr(v)
1220
+ 'pi'
1221
+ sage: v.__repr__()
1222
+ 'pi'
1223
+ """
1224
+ return repr(self._value)
1225
+
1226
+ cdef class ExpressionVariable(Expression):
1227
+ r"""
1228
+ An Expression that represents a variable.
1229
+
1230
+ EXAMPLES::
1231
+
1232
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1233
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1234
+ sage: type(etb.var(x)) # needs sage.symbolic
1235
+ <class 'sage.ext.fast_callable.ExpressionVariable'>
1236
+ """
1237
+ cdef int _variable_index
1238
+
1239
+ def __init__(self, etb, int n):
1240
+ r"""
1241
+ Initialize an ExpressionVariable.
1242
+
1243
+ EXAMPLES::
1244
+
1245
+ sage: # needs sage.symbolic
1246
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionVariable
1247
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1248
+ sage: etb(x)
1249
+ v_0
1250
+ sage: v = ExpressionVariable(etb, 0); v
1251
+ v_0
1252
+ sage: v._get_etb() is etb
1253
+ True
1254
+ sage: v.variable_index()
1255
+ 0
1256
+ """
1257
+ Expression.__init__(self, etb)
1258
+ self._variable_index = n
1259
+
1260
+ def variable_index(self):
1261
+ r"""
1262
+ Return the variable index of an :class:`ExpressionVariable`.
1263
+
1264
+ EXAMPLES::
1265
+
1266
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1267
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1268
+ sage: etb(x).variable_index() # needs sage.symbolic
1269
+ 0
1270
+ """
1271
+ return self._variable_index
1272
+
1273
+ def __repr__(self):
1274
+ r"""
1275
+ Give a string representing this :class:`ExpressionVariable`.
1276
+
1277
+ EXAMPLES::
1278
+
1279
+ sage: # needs sage.symbolic
1280
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1281
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1282
+ sage: v = etb._var_number(0)
1283
+ sage: v
1284
+ v_0
1285
+ sage: repr(v)
1286
+ 'v_0'
1287
+ sage: v.__repr__()
1288
+ 'v_0'
1289
+ """
1290
+ # Should we look up the variable name in self._etb, instead?
1291
+ # I think not.. I like the emphasis that we're totally removed
1292
+ # from the original expression when we have an Expression.
1293
+ return "v_%d" % self._variable_index
1294
+
1295
+
1296
+ cdef class ExpressionCall(Expression):
1297
+ r"""
1298
+ An Expression that represents a function call.
1299
+
1300
+ EXAMPLES::
1301
+
1302
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1303
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1304
+ sage: type(etb.call(sin, x)) # needs sage.symbolic
1305
+ <class 'sage.ext.fast_callable.ExpressionCall'>
1306
+ """
1307
+ cdef object _function
1308
+ cdef object _arguments
1309
+
1310
+ def __init__(self, etb, fn, args):
1311
+ r"""
1312
+ Initialize an :class:`ExpressionCall`.
1313
+
1314
+ EXAMPLES::
1315
+
1316
+ sage: # needs sage.symbolic
1317
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionCall
1318
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1319
+ sage: x = etb(x)
1320
+ sage: etb.call(factorial, x)
1321
+ {factorial}(v_0)
1322
+ sage: v = ExpressionCall(etb, factorial, [x]); v
1323
+ {factorial}(v_0)
1324
+ sage: v._get_etb() is etb
1325
+ True
1326
+ sage: v.function()
1327
+ factorial
1328
+ sage: v.arguments()
1329
+ [v_0]
1330
+ """
1331
+ Expression.__init__(self, etb)
1332
+ self._function = fn
1333
+ self._arguments = args
1334
+
1335
+ def function(self):
1336
+ r"""
1337
+ Return the function from this :class:`ExpressionCall`.
1338
+
1339
+ EXAMPLES::
1340
+
1341
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1342
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1343
+ sage: etb.call(sin, x).function() # needs sage.symbolic
1344
+ sin
1345
+ """
1346
+ return self._function
1347
+
1348
+ def arguments(self):
1349
+ r"""
1350
+ Return the arguments from this :class:`ExpressionCall`.
1351
+
1352
+ EXAMPLES::
1353
+
1354
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1355
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1356
+ sage: etb.call(sin, x).arguments() # needs sage.symbolic
1357
+ [v_0]
1358
+ """
1359
+ return copy(self._arguments)
1360
+
1361
+ def __repr__(self):
1362
+ r"""
1363
+ Give a string representing this :class:`ExpressionCall`.
1364
+
1365
+ EXAMPLES::
1366
+
1367
+ sage: # needs sage.symbolic
1368
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1369
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1370
+ sage: x = etb.var(x)
1371
+ sage: etb.call(operator.add, x, 1)
1372
+ add(v_0, 1)
1373
+ sage: etb.call(factorial, x)
1374
+ {factorial}(v_0)
1375
+ sage: v = etb.call(sin, x)
1376
+ sage: v
1377
+ sin(v_0)
1378
+ sage: repr(v)
1379
+ 'sin(v_0)'
1380
+ sage: v.__repr__()
1381
+ 'sin(v_0)'
1382
+ """
1383
+ fn = function_name(self._function)
1384
+ return '%s(%s)' % (fn, ', '.join(repr(a) for a in self._arguments))
1385
+
1386
+
1387
+ cdef class ExpressionIPow(Expression):
1388
+ r"""
1389
+ A power Expression with an integer exponent.
1390
+
1391
+ EXAMPLES::
1392
+
1393
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1394
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1395
+ sage: type(etb.var('x')^17) # needs sage.symbolic
1396
+ <class 'sage.ext.fast_callable.ExpressionIPow'>
1397
+ """
1398
+ cdef object _base
1399
+ cdef object _exponent
1400
+
1401
+ def __init__(self, etb, base, exponent):
1402
+ r"""
1403
+ Initialize an ExpressionIPow.
1404
+
1405
+ EXAMPLES::
1406
+
1407
+ sage: # needs sage.symbolic
1408
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionIPow
1409
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1410
+ sage: x = etb(x)
1411
+ sage: x^(-12)
1412
+ ipow(v_0, -12)
1413
+ sage: v = ExpressionIPow(etb, x, 55); v
1414
+ ipow(v_0, 55)
1415
+ sage: v._get_etb() is etb
1416
+ True
1417
+ sage: v.base()
1418
+ v_0
1419
+ sage: v.exponent()
1420
+ 55
1421
+ """
1422
+ Expression.__init__(self, etb)
1423
+ self._base = base
1424
+ self._exponent = exponent
1425
+
1426
+ def base(self):
1427
+ r"""
1428
+ Return the base from this :class:`ExpressionIPow`.
1429
+
1430
+ EXAMPLES::
1431
+
1432
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1433
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1434
+ sage: (etb(33)^42).base() # needs sage.symbolic
1435
+ 33
1436
+ """
1437
+ return self._base
1438
+
1439
+ def exponent(self):
1440
+ r"""
1441
+ Return the exponent from this :class:`ExpressionIPow`.
1442
+
1443
+ EXAMPLES::
1444
+
1445
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1446
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1447
+ sage: (etb(x)^(-1)).exponent() # needs sage.symbolic
1448
+ -1
1449
+ """
1450
+ return self._exponent
1451
+
1452
+ def __repr__(self):
1453
+ r"""
1454
+ Give a string representing this :class:`ExpressionIPow`.
1455
+
1456
+ EXAMPLES::
1457
+
1458
+ sage: # needs sage.symbolic
1459
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1460
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1461
+ sage: x = etb.var(x)
1462
+ sage: x^3
1463
+ ipow(v_0, 3)
1464
+ sage: x^(-2)
1465
+ ipow(v_0, -2)
1466
+ sage: v = (x+1)^3
1467
+ sage: v
1468
+ ipow(add(v_0, 1), 3)
1469
+ sage: repr(v)
1470
+ 'ipow(add(v_0, 1), 3)'
1471
+ sage: v.__repr__()
1472
+ 'ipow(add(v_0, 1), 3)'
1473
+ """
1474
+ return 'ipow(%s, %d)' % (repr(self._base), self._exponent)
1475
+
1476
+
1477
+ cdef class ExpressionChoice(Expression):
1478
+ r"""
1479
+ A conditional expression.
1480
+
1481
+ (It's possible to create choice nodes, but they don't work yet.)
1482
+
1483
+ EXAMPLES::
1484
+
1485
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1486
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1487
+ sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) # needs sage.symbolic
1488
+ (0 if {eq}(v_0, 0) else div(1, v_0))
1489
+ """
1490
+
1491
+ cdef object _cond
1492
+ cdef object _iftrue
1493
+ cdef object _iffalse
1494
+
1495
+ def __init__(self, etb, cond, iftrue, iffalse):
1496
+ r"""
1497
+ Initialize an :class:`ExpressionChoice`.
1498
+
1499
+ EXAMPLES::
1500
+
1501
+ sage: # needs sage.symbolic
1502
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionChoice
1503
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1504
+ sage: x = etb(x)
1505
+ sage: etb.choice(x, ~x, 0)
1506
+ (inv(v_0) if v_0 else 0)
1507
+ sage: v = ExpressionChoice(etb, x, ~x, etb(0)); v
1508
+ (inv(v_0) if v_0 else 0)
1509
+ sage: v._get_etb() is etb
1510
+ True
1511
+ sage: v.condition()
1512
+ v_0
1513
+ sage: v.if_true()
1514
+ inv(v_0)
1515
+ sage: v.if_false()
1516
+ 0
1517
+ """
1518
+ Expression.__init__(self, etb)
1519
+ self._cond = cond
1520
+ self._iftrue = iftrue
1521
+ self._iffalse = iffalse
1522
+
1523
+ def condition(self):
1524
+ r"""
1525
+ Return the condition of an :class:`ExpressionChoice`.
1526
+
1527
+ EXAMPLES::
1528
+
1529
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1530
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1531
+ sage: x = etb(x) # needs sage.symbolic
1532
+ sage: etb.choice(x, ~x, 0).condition() # needs sage.symbolic
1533
+ v_0
1534
+ """
1535
+ return self._cond
1536
+
1537
+ def if_true(self):
1538
+ r"""
1539
+ Return the true branch of an :class:`ExpressionChoice`.
1540
+
1541
+ EXAMPLES::
1542
+
1543
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1544
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1545
+ sage: x = etb(x) # needs sage.symbolic
1546
+ sage: etb.choice(x, ~x, 0).if_true() # needs sage.symbolic
1547
+ inv(v_0)
1548
+ """
1549
+ return self._iftrue
1550
+
1551
+ def if_false(self):
1552
+ r"""
1553
+ Return the false branch of an :class:`ExpressionChoice`.
1554
+
1555
+ EXAMPLES::
1556
+
1557
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1558
+ sage: etb = ExpressionTreeBuilder(vars=(x,)) # needs sage.symbolic
1559
+ sage: x = etb(x) # needs sage.symbolic
1560
+ sage: etb.choice(x, ~x, 0).if_false() # needs sage.symbolic
1561
+ 0
1562
+ """
1563
+ return self._iffalse
1564
+
1565
+ def __repr__(self):
1566
+ r"""
1567
+ Give a string representation for this :class:`ExpressionChoice`.
1568
+ (Based on the syntax for Python conditional expressions.)
1569
+
1570
+ EXAMPLES::
1571
+
1572
+ sage: # needs sage.symbolic
1573
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1574
+ sage: etb = ExpressionTreeBuilder(vars=(x,))
1575
+ sage: x = etb(x)
1576
+ sage: v = etb.choice(x, ~x, 0)
1577
+ sage: v
1578
+ (inv(v_0) if v_0 else 0)
1579
+ sage: repr(v)
1580
+ '(inv(v_0) if v_0 else 0)'
1581
+ sage: v.__repr__()
1582
+ '(inv(v_0) if v_0 else 0)'
1583
+ """
1584
+ return '(%s if %s else %s)' % (repr(self._iftrue),
1585
+ repr(self._cond),
1586
+ repr(self._iffalse))
1587
+
1588
+
1589
+ cpdef _expression_binop_helper(s, o, op):
1590
+ r"""
1591
+ Make an :class:`Expression` for (``s`` ``op`` ``o``).
1592
+
1593
+ Either ``s`` or ``o`` (or both) must already be an :class:`Expression`.
1594
+
1595
+ EXAMPLES::
1596
+
1597
+ sage: from sage.ext.fast_callable import _expression_binop_helper, ExpressionTreeBuilder
1598
+ sage: var('x,y') # needs sage.symbolic
1599
+ (x, y)
1600
+ sage: etb = ExpressionTreeBuilder(vars=(x,y)) # needs sage.symbolic
1601
+ sage: x = etb(x) # needs sage.symbolic
1602
+
1603
+ Now ``x`` is an :class:`Expression`, but ``y`` is not. Still, all the following
1604
+ cases work::
1605
+
1606
+ sage: _expression_binop_helper(x, x, operator.add) # needs sage.symbolic
1607
+ add(v_0, v_0)
1608
+ sage: _expression_binop_helper(x, y, operator.add) # needs sage.symbolic
1609
+ add(v_0, v_1)
1610
+ sage: _expression_binop_helper(y, x, operator.add) # needs sage.symbolic
1611
+ add(v_1, v_0)
1612
+ """
1613
+ # The Cython way of handling operator overloading on cdef classes
1614
+ # (which is inherited from Python) is quite annoying. Inside the
1615
+ # code for a binary operator, you know that either the first or
1616
+ # second argument (or both) is a member of your class, but you
1617
+ # don't know which.
1618
+
1619
+ # If there is an arithmetic operator between an Expression and
1620
+ # a non-Expression, I want to convert the non-Expression into
1621
+ # an Expression. But to do that, I need the ExpressionTreeBuilder
1622
+ # from the Expression.
1623
+
1624
+ cdef Expression self
1625
+ cdef Expression other
1626
+
1627
+ if not isinstance(o, Expression):
1628
+ self = s
1629
+ other = self._etb(o)
1630
+ elif not isinstance(s, Expression):
1631
+ other = o
1632
+ self = other._etb(s)
1633
+ else:
1634
+ self = s
1635
+ other = o
1636
+ assert self._etb is other._etb
1637
+
1638
+ return ExpressionCall(self._etb, op, [self, other])
1639
+
1640
+
1641
+ class IntegerPowerFunction():
1642
+ r"""
1643
+ This class represents the function `x^n` for an arbitrary integral power `n`.
1644
+
1645
+ That is, ``IntegerPowerFunction(2)`` is the squaring function;
1646
+ ``IntegerPowerFunction(-1)`` is the reciprocal function.
1647
+
1648
+ EXAMPLES::
1649
+
1650
+ sage: from sage.ext.fast_callable import IntegerPowerFunction
1651
+ sage: square = IntegerPowerFunction(2)
1652
+ sage: square
1653
+ (^2)
1654
+ sage: square(pi) # needs sage.symbolic
1655
+ pi^2
1656
+ sage: square(I) # needs sage.symbolic
1657
+ -1
1658
+ sage: square(RIF(-1, 1)).str(style='brackets') # needs sage.rings.real_interval_field
1659
+ '[0.0000000000000000 .. 1.0000000000000000]'
1660
+ sage: IntegerPowerFunction(-1)
1661
+ (^(-1))
1662
+ sage: IntegerPowerFunction(-1)(22/7)
1663
+ 7/22
1664
+ sage: v = Integers(123456789)(54321)
1665
+ sage: v^9876543210
1666
+ 79745229
1667
+ sage: IntegerPowerFunction(9876543210)(v)
1668
+ 79745229
1669
+ """
1670
+
1671
+ def __init__(self, n):
1672
+ r"""
1673
+ Initialize an :class:`IntegerPowerFunction`.
1674
+
1675
+ EXAMPLES::
1676
+
1677
+ sage: from sage.ext.fast_callable import IntegerPowerFunction
1678
+ sage: cube = IntegerPowerFunction(3)
1679
+ sage: cube
1680
+ (^3)
1681
+ sage: cube(AA(7)^(1/3)) # needs sage.rings.number_field
1682
+ 7.000000000000000?
1683
+ sage: cube.exponent
1684
+ 3
1685
+ """
1686
+ self.exponent = n
1687
+
1688
+ def __repr__(self):
1689
+ r"""
1690
+ Return a string representing this :class:`IntegerPowerFunction`.
1691
+
1692
+ EXAMPLES::
1693
+
1694
+ sage: from sage.ext.fast_callable import IntegerPowerFunction
1695
+ sage: square = IntegerPowerFunction(2)
1696
+ sage: square
1697
+ (^2)
1698
+ sage: repr(square)
1699
+ '(^2)'
1700
+ sage: square.__repr__()
1701
+ '(^2)'
1702
+ sage: repr(IntegerPowerFunction(-57))
1703
+ '(^(-57))'
1704
+ """
1705
+ if self.exponent >= 0:
1706
+ return "(^%s)" % self.exponent
1707
+ else:
1708
+ return "(^(%s))" % self.exponent
1709
+
1710
+ def __call__(self, x):
1711
+ r"""
1712
+ Call this :class:`IntegerPowerFunction`, to compute a power of its argument.
1713
+
1714
+ EXAMPLES::
1715
+
1716
+ sage: from sage.ext.fast_callable import IntegerPowerFunction
1717
+ sage: square = IntegerPowerFunction(2)
1718
+ sage: square.__call__(5)
1719
+ 25
1720
+ sage: square(5)
1721
+ 25
1722
+ """
1723
+ return x**self.exponent
1724
+
1725
+
1726
+ cdef dict builtin_functions = None
1727
+ cpdef dict get_builtin_functions():
1728
+ r"""
1729
+ Return a dictionary from Sage and Python functions to opcode names.
1730
+
1731
+ The result is cached.
1732
+
1733
+ The dictionary is used in :class:`ExpressionCall`.
1734
+
1735
+ EXAMPLES::
1736
+
1737
+ sage: from sage.ext.fast_callable import get_builtin_functions
1738
+ sage: builtins = get_builtin_functions()
1739
+ sage: sorted(set(builtins.values())) # needs sage.symbolic
1740
+ ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atanh', 'ceil',
1741
+ 'cos', 'cosh', 'cot', 'csc', 'div', 'exp', 'floor', 'floordiv', 'inv', 'log',
1742
+ 'mul', 'neg', 'pow', 'sec', 'sin', 'sinh', 'sqrt', 'sub', 'tan', 'tanh']
1743
+ sage: builtins[sin] # needs sage.symbolic
1744
+ 'sin'
1745
+ sage: builtins[ln] # needs sage.symbolic
1746
+ 'log'
1747
+ """
1748
+ # We delay building builtin_functions to break a circular import
1749
+ # between sage.functions and this file.
1750
+ global builtin_functions
1751
+ if builtin_functions is not None:
1752
+ return builtin_functions
1753
+ builtin_functions = {
1754
+ op_add: 'add',
1755
+ op_sub: 'sub',
1756
+ op_mul: 'mul',
1757
+ op_div: 'div',
1758
+ op_truediv: 'div',
1759
+ op_floordiv: 'floordiv',
1760
+ op_abs: 'abs',
1761
+ op_neg: 'neg',
1762
+ op_inv: 'inv',
1763
+ op_pow: 'pow',
1764
+ }
1765
+
1766
+ try:
1767
+ import sage.functions.all as func_all
1768
+ except ImportError:
1769
+ pass
1770
+ else:
1771
+ # not handled: atan2, log2, log10
1772
+ for fn in ('sqrt', 'ceil', 'floor',
1773
+ 'sin', 'cos', 'tan', 'sec', 'csc', 'cot',
1774
+ 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',
1775
+ 'asinh', 'acosh', 'atanh', 'exp', 'log'):
1776
+ builtin_functions[getattr(func_all, fn)] = fn
1777
+ builtin_functions[func_all.abs_symbolic] = 'abs'
1778
+ builtin_functions[func_all.ln] = 'log'
1779
+ return builtin_functions
1780
+
1781
+
1782
+ cdef class InstructionStream # forward declaration
1783
+
1784
+
1785
+ cpdef generate_code(Expression expr, InstructionStream stream):
1786
+ r"""
1787
+ Generate code from an :class:`Expression` tree; write the result into an
1788
+ :class:`InstructionStream`.
1789
+
1790
+ In :func:`fast_callable`, first we create an :class:`Expression`, either directly
1791
+ with an :class:`ExpressionTreeBuilder` or with :meth:`_fast_callable_` methods.
1792
+ Then we optimize the :class:`Expression` in tree form. (Unfortunately,
1793
+ this step is currently missing -- we do no optimizations.)
1794
+
1795
+ Then we linearize the :class:`Expression` into a sequence of instructions,
1796
+ by walking the :class:`Expression` and sending the corresponding stack
1797
+ instructions to an :class:`InstructionStream`.
1798
+
1799
+ EXAMPLES::
1800
+
1801
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, generate_code, InstructionStream
1802
+
1803
+ sage: # needs sage.symbolic
1804
+ sage: etb = ExpressionTreeBuilder('x')
1805
+ sage: x = etb.var('x')
1806
+ sage: expr = (x+pi) * (x+1)
1807
+ sage: from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py
1808
+ sage: instr_stream = InstructionStream(metadata, 1)
1809
+ sage: generate_code(expr, instr_stream)
1810
+ sage: instr_stream.instr('return')
1811
+ sage: v = Wrapper_py(instr_stream.get_current())
1812
+ sage: type(v)
1813
+ <class '...interpreters.wrapper_py.Wrapper_py'>
1814
+ sage: v(7)
1815
+ 8*pi + 56
1816
+
1817
+ TESTS::
1818
+
1819
+ sage: def my_sin(x): return sin(x)
1820
+ sage: def my_norm(x, y): return x*x + y*y
1821
+ sage: def my_sqrt(x):
1822
+ ....: if x < 0: raise ValueError("sqrt of negative number")
1823
+ ....: return sqrt(x, extend=False)
1824
+
1825
+ sage: # needs sage.symbolic
1826
+ sage: fc = fast_callable(expr, domain=RealField(130))
1827
+ sage: fc(0)
1828
+ 3.1415926535897932384626433832795028842
1829
+ sage: fc(1)
1830
+ 8.2831853071795864769252867665590057684
1831
+ sage: fc = fast_callable(expr, domain=RDF)
1832
+ sage: fc(0)
1833
+ 3.141592653589793
1834
+ sage: fc(1)
1835
+ 8.283185307179586
1836
+ sage: fc.op_list()
1837
+ [('load_arg', 0), ('load_const', pi), 'add', ('load_arg', 0), ('load_const', 1), 'add', 'mul', 'return']
1838
+ sage: fc = fast_callable(etb.call(sin, x) + etb.call(sqrt, x), domain=RDF)
1839
+ sage: fc(1)
1840
+ 1.8414709848078965
1841
+ sage: fc.op_list()
1842
+ [('load_arg', 0), 'sin', ('load_arg', 0), 'sqrt', 'add', 'return']
1843
+ sage: fc = fast_callable(etb.call(sin, x) + etb.call(sqrt, x))
1844
+ sage: fc(1)
1845
+ sin(1) + 1
1846
+ sage: fc.op_list()
1847
+ [('load_arg', 0), ('py_call', sin, 1), ('load_arg', 0), ('py_call', <function sqrt at ...>, 1), 'add', 'return']
1848
+ sage: fc = fast_callable(etb.call(my_sin, x), domain=RDF)
1849
+ sage: fc(3)
1850
+ 0.1411200080598672
1851
+
1852
+ sage: # needs sage.rings.real_mpfr sage.symbolic
1853
+ sage: fc = fast_callable(etb.call(my_sin, x), domain=RealField(100))
1854
+ sage: fc(3)
1855
+ 0.14112000805986722210074480281
1856
+ sage: fc.op_list()
1857
+ [('load_arg', 0), ('py_call', <function my_sin at 0x...>, 1), 'return']
1858
+
1859
+ sage: # needs sage.symbolic
1860
+ sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RDF)
1861
+ sage: fc(3)
1862
+ 1.7320508075688772
1863
+ sage: parent(fc(3))
1864
+ Real Double Field
1865
+ sage: fc(-3)
1866
+ Traceback (most recent call last):
1867
+ ...
1868
+ ValueError: sqrt of negative number
1869
+ sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RR)
1870
+ sage: fc(3)
1871
+ 1.73205080756888
1872
+ sage: fc(-3)
1873
+ Traceback (most recent call last):
1874
+ ...
1875
+ ValueError: sqrt of negative number
1876
+
1877
+ sage: etb2 = ExpressionTreeBuilder(('y','z'))
1878
+ sage: y = etb2.var('y')
1879
+ sage: z = etb2.var('z')
1880
+ sage: fc = fast_callable(etb2.call(sqrt, etb2.call(my_norm, y, z)), domain=RDF)
1881
+ sage: fc(3, 4)
1882
+ 5.0
1883
+ sage: fc.op_list()
1884
+ [('load_arg', 0), ('load_arg', 1), ('py_call', <function my_norm at 0x...>, 2), 'sqrt', 'return']
1885
+ sage: fc.python_calls()
1886
+ [<function my_norm at 0x...>]
1887
+ sage: fc = fast_callable(etb2.call(sqrt, etb2.call(my_norm, y, z)), domain=RR) # needs sage.rings.real_mpfr
1888
+ sage: fc(3, 4) # needs sage.rings.real_mpfr
1889
+ 5.00000000000000
1890
+ sage: fc = fast_callable(etb2.call(my_norm, y, z), domain=ZZ)
1891
+ sage: fc(3, 4)
1892
+ 25
1893
+ sage: fc.op_list()
1894
+ [('load_arg', 0), ('load_arg', 1), ('py_call', <function my_norm at 0x...>, 2), 'return']
1895
+
1896
+ sage: # needs sage.symbolic
1897
+ sage: fc = fast_callable(expr)
1898
+ sage: fc(3.0r)
1899
+ 4.0*pi + 12.0
1900
+ sage: fc = fast_callable(x+3, domain=ZZ)
1901
+ sage: fc(4)
1902
+ 7
1903
+ sage: fc = fast_callable(x/3, domain=ZZ)
1904
+ sage: fc(4)
1905
+ Traceback (most recent call last):
1906
+ ...
1907
+ TypeError: no conversion of this rational to integer
1908
+ sage: fc(6)
1909
+ 2
1910
+ sage: fc = fast_callable(etb.call(sin, x), domain=ZZ)
1911
+ sage: fc(0)
1912
+ 0
1913
+ sage: fc(3)
1914
+ Traceback (most recent call last):
1915
+ ...
1916
+ TypeError: unable to convert sin(3) to an integer
1917
+
1918
+ ::
1919
+
1920
+ sage: # needs sage.symbolic
1921
+ sage: fc = fast_callable(etb(x)^100)
1922
+ sage: fc(pi)
1923
+ pi^100
1924
+ sage: fc = fast_callable(etb(x)^100, domain=ZZ)
1925
+ sage: fc(2)
1926
+ 1267650600228229401496703205376
1927
+ sage: fc = fast_callable(etb(x)^100, domain=RIF)
1928
+ sage: fc(RIF(-2))
1929
+ 1.2676506002282295?e30
1930
+ sage: fc = fast_callable(etb(x)^100, domain=RDF)
1931
+ sage: fc.op_list()
1932
+ [('load_arg', 0), ('ipow', 100), 'return']
1933
+ sage: fc(1.1)
1934
+ 13780.61233982...
1935
+ sage: fc = fast_callable(etb(x)^100, domain=RR) # needs sage.rings.real_mpfr
1936
+ sage: fc.op_list() # needs sage.rings.real_mpfr
1937
+ [('load_arg', 0), ('ipow', 100), 'return']
1938
+ sage: fc(1.1) # needs sage.rings.real_mpfr
1939
+ 13780.6123398224
1940
+ sage: fc = fast_callable(etb(x)^(-100), domain=RDF)
1941
+ sage: fc.op_list()
1942
+ [('load_arg', 0), ('ipow', -100), 'return']
1943
+ sage: fc(1.1)
1944
+ 7.25657159014...e-05
1945
+ sage: fc = fast_callable(etb(x)^(-100), domain=RR) # needs sage.rings.real_mpfr
1946
+ sage: fc(1.1) # needs sage.rings.real_mpfr
1947
+ 0.0000725657159014814
1948
+ sage: expo = 2^32
1949
+ sage: base = (1.0).nextabove()
1950
+ sage: fc = fast_callable(etb(x)^expo, domain=RDF)
1951
+ sage: fc.op_list()
1952
+ [('load_arg', 0), ('py_call', (^4294967296), 1), 'return']
1953
+ sage: fc(base) # rel tol 1e-15
1954
+ 1.0000009536747712
1955
+ sage: RDF(base)^expo
1956
+ 1.0000009536747712
1957
+ sage: fc = fast_callable(etb(x)^expo, domain=RR) # needs sage.rings.real_mpfr
1958
+ sage: fc.op_list() # needs sage.rings.real_mpfr
1959
+ [('load_arg', 0), ('py_call', (^4294967296), 1), 'return']
1960
+ sage: fc(base) # needs sage.rings.real_mpfr
1961
+ 1.00000095367477
1962
+ sage: base^expo
1963
+ 1.00000095367477
1964
+
1965
+ Make sure we do not overflow the stack with highly nested expressions
1966
+ (:issue:`11766`)::
1967
+
1968
+ sage: # needs sage.rings.real_mpfr
1969
+ sage: R.<x> = CC[]
1970
+ sage: f = R(list(range(100000)))
1971
+ sage: ff = fast_callable(f)
1972
+ sage: f(0.5)
1973
+ 2.00000000000000
1974
+ sage: ff(0.5)
1975
+ 2.00000000000000
1976
+ sage: f(0.9), ff(0.9)
1977
+ (90.0000000000000, 90.0000000000000)
1978
+ """
1979
+ cdef ExpressionConstant econst
1980
+ cdef ExpressionVariable evar
1981
+ cdef ExpressionCall ecall
1982
+ cdef ExpressionChoice echoice
1983
+
1984
+ # Maintain our own stack to avoid crashing on deeply-nested expressions.
1985
+ cdef list todo = [expr]
1986
+ do_call = Expression(None)
1987
+ while len(todo):
1988
+ expr = todo.pop()
1989
+ if isinstance(expr, ExpressionConstant):
1990
+ econst = expr
1991
+ stream.load_const(econst._value)
1992
+ elif isinstance(expr, ExpressionVariable):
1993
+ evar = expr
1994
+ stream.load_arg(evar._variable_index)
1995
+ elif isinstance(expr, ExpressionCall):
1996
+ ecall = expr
1997
+ todo.append(expr)
1998
+ todo.append(do_call)
1999
+ for arg in reversed(ecall._arguments):
2000
+ todo.append(arg)
2001
+ continue
2002
+ elif expr is do_call:
2003
+ # arguments already evaluated, make the call
2004
+ ecall = todo.pop()
2005
+ fn = ecall._function
2006
+ opname = get_builtin_functions().get(fn)
2007
+ if opname is not None:
2008
+ if stream.has_instr(opname):
2009
+ stream.instr0(opname, ())
2010
+ continue
2011
+ if stream.has_instr('py_call'):
2012
+ stream.instr('py_call', fn, len(ecall._arguments))
2013
+ else:
2014
+ raise ValueError("Unhandled function %s in generate_code" % fn)
2015
+ elif isinstance(expr, ExpressionIPow):
2016
+ base = expr.base()
2017
+ exponent = expr.exponent()
2018
+ metadata = stream.get_metadata()
2019
+ ipow_range = metadata.ipow_range
2020
+ if ipow_range is True:
2021
+ use_ipow = True
2022
+ elif isinstance(ipow_range, tuple):
2023
+ a,b = ipow_range
2024
+ use_ipow = (a <= exponent <= b)
2025
+ else:
2026
+ use_ipow = False
2027
+ generate_code(base, stream)
2028
+ if use_ipow:
2029
+ stream.instr('ipow', exponent)
2030
+ else:
2031
+ stream.instr('py_call', IntegerPowerFunction(exponent), 1)
2032
+ else:
2033
+ raise ValueError("Unhandled expression kind %s in generate_code" % type(expr))
2034
+
2035
+
2036
+ cdef class InterpreterMetadata # forward declaration
2037
+
2038
+
2039
+ cdef class InstructionStream:
2040
+ r"""
2041
+ An :class:`InstructionStream` takes a sequence of instructions (passed in by
2042
+ a series of method calls) and computes the data structures needed
2043
+ by the interpreter. This is the stage where we switch from operating
2044
+ on :class:`Expression` trees to a linear representation. If we had a peephole
2045
+ optimizer (we don't) it would go here.
2046
+
2047
+ Currently, this class is not very general; it only works for
2048
+ interpreters with a fixed set of memory chunks (with fixed names).
2049
+ Basically, it only works for stack-based expression interpreters.
2050
+ It should be generalized, so that the interpreter metadata includes
2051
+ a description of the memory chunks involved and the instruction stream
2052
+ can handle any interpreter.
2053
+
2054
+ Once you're done adding instructions, you call :meth:`get_current` to retrieve
2055
+ the information needed by the interpreter (as a Python dictionary).
2056
+ """
2057
+
2058
+ cdef InterpreterMetadata _metadata
2059
+ cdef list _instrs
2060
+ cdef list _bytecode
2061
+ cdef list _constants
2062
+ cdef object _constant_locs
2063
+ cdef object _py_constants
2064
+ cdef object _py_constant_locs
2065
+ cdef int _stack_cur_size
2066
+ cdef int _stack_max_size
2067
+ cdef int _n_args
2068
+ cdef object _domain
2069
+
2070
+ def __init__(self, metadata, n_args, domain=None):
2071
+ r"""
2072
+ Initialize an :class:`InstructionStream`.
2073
+
2074
+ INPUT:
2075
+
2076
+ - ``metadata`` -- the ``metadata_by_opname`` from a wrapper module
2077
+
2078
+ - ``n_args`` -- the number of arguments accessible by the generated code
2079
+ (this is just passed to the wrapper class)
2080
+
2081
+ - ``domain`` -- the domain of interpretation (this is just passed to the
2082
+ wrapper class)
2083
+
2084
+ EXAMPLES::
2085
+
2086
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2087
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2088
+ sage: from sage.ext.fast_callable import InstructionStream
2089
+ sage: instr_stream = InstructionStream(metadata, 1)
2090
+ sage: instr_stream.get_current()
2091
+ {'args': 1,
2092
+ 'code': [],
2093
+ 'constants': [],
2094
+ 'domain': None,
2095
+ 'py_constants': [],
2096
+ 'stack': 0}
2097
+ sage: md = instr_stream.get_metadata()
2098
+ sage: type(md)
2099
+ <class 'sage.ext.fast_callable.InterpreterMetadata'>
2100
+ sage: md.by_opname['py_call']
2101
+ (CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']), 3)
2102
+ sage: md.by_opcode[3]
2103
+ ('py_call', CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']))
2104
+ """
2105
+ self._metadata = metadata
2106
+ self._instrs = []
2107
+ self._bytecode = []
2108
+ self._constants = []
2109
+ self._constant_locs = {}
2110
+ self._py_constants = []
2111
+ self._py_constant_locs = {}
2112
+ self._stack_cur_size = 0
2113
+ self._stack_max_size = 0
2114
+ self._domain = domain
2115
+ self._n_args = n_args
2116
+
2117
+ def load_const(self, c):
2118
+ r"""
2119
+ Add a ``'load_const'`` instruction to this :class:`InstructionStream`.
2120
+
2121
+ EXAMPLES::
2122
+
2123
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2124
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2125
+ sage: from sage.ext.fast_callable import InstructionStream, op_list
2126
+ sage: instr_stream = InstructionStream(metadata, 1)
2127
+ sage: instr_stream.load_const(5)
2128
+ sage: instr_stream.current_op_list()
2129
+ [('load_const', 5)]
2130
+ sage: instr_stream.load_const(7)
2131
+ sage: instr_stream.load_const(5)
2132
+ sage: instr_stream.current_op_list()
2133
+ [('load_const', 5), ('load_const', 7), ('load_const', 5)]
2134
+
2135
+ Note that constants are shared: even though we load 5 twice, it
2136
+ only appears once in the constant table. ::
2137
+
2138
+ sage: instr_stream.get_current()['constants']
2139
+ [5, 7]
2140
+ """
2141
+ self.instr('load_const', c)
2142
+
2143
+ def load_arg(self, n):
2144
+ r"""
2145
+ Add a ``'load_arg'`` instruction to this :class:`InstructionStream`.
2146
+
2147
+ EXAMPLES::
2148
+
2149
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2150
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2151
+ sage: from sage.ext.fast_callable import InstructionStream
2152
+ sage: instr_stream = InstructionStream(metadata, 12)
2153
+ sage: instr_stream.load_arg(5)
2154
+ sage: instr_stream.current_op_list()
2155
+ [('load_arg', 5)]
2156
+ sage: instr_stream.load_arg(3)
2157
+ sage: instr_stream.current_op_list()
2158
+ [('load_arg', 5), ('load_arg', 3)]
2159
+ """
2160
+ self.instr('load_arg', n)
2161
+
2162
+ cpdef bint has_instr(self, opname) noexcept:
2163
+ r"""
2164
+ Check whether this :class:`InstructionStream` knows how to generate code
2165
+ for a given instruction.
2166
+
2167
+ EXAMPLES::
2168
+
2169
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2170
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2171
+ sage: from sage.ext.fast_callable import InstructionStream
2172
+ sage: instr_stream = InstructionStream(metadata, 1)
2173
+ sage: instr_stream.has_instr('return')
2174
+ True
2175
+ sage: instr_stream.has_instr('factorial')
2176
+ False
2177
+ sage: instr_stream.has_instr('abs')
2178
+ True
2179
+ """
2180
+ return (opname in self._metadata.by_opname)
2181
+
2182
+ def instr(self, opname, *args):
2183
+ r"""
2184
+ Generate code in this :class:`InstructionStream` for the given instruction
2185
+ and arguments.
2186
+
2187
+ The opname is used to look up a :class:`CompilerInstrSpec`; the
2188
+ :class:`CompilerInstrSpec` describes how to interpret the arguments.
2189
+ (This is documented in the class docstring for :class:`CompilerInstrSpec`.)
2190
+
2191
+ EXAMPLES::
2192
+
2193
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2194
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2195
+ sage: from sage.ext.fast_callable import InstructionStream
2196
+ sage: instr_stream = InstructionStream(metadata, 1)
2197
+ sage: instr_stream.instr('load_arg', 0)
2198
+ sage: instr_stream.instr('sin') # needs sage.symbolic
2199
+ sage: instr_stream.instr('py_call', math.sin, 1)
2200
+ sage: instr_stream.instr('abs') # needs sage.symbolic
2201
+ sage: instr_stream.instr('factorial')
2202
+ Traceback (most recent call last):
2203
+ ...
2204
+ KeyError: 'factorial'
2205
+ sage: instr_stream.instr('return')
2206
+ sage: instr_stream.current_op_list() # needs sage.symbolic
2207
+ [('load_arg', 0), 'sin', ('py_call', <built-in function sin>, 1), 'abs', 'return']
2208
+ """
2209
+ self.instr0(opname, args)
2210
+
2211
+ cdef instr0(self, opname, tuple args):
2212
+ """
2213
+ Cdef version of instr. (Can't cpdef because of star args.)
2214
+ """
2215
+ cdef int i
2216
+
2217
+ spec, opcode = self._metadata.by_opname[opname]
2218
+ assert len(spec.parameters) == len(args)
2219
+
2220
+ cdef int n_inputs = spec.n_inputs
2221
+ cdef int n_outputs = spec.n_outputs
2222
+
2223
+ self._bytecode.append(opcode)
2224
+ for i in range(len(args)):
2225
+ if spec.parameters[i] == 'constants':
2226
+ # XXX bad for strict-mode floating-point constants
2227
+ # (doesn't handle signed 0, NaN)
2228
+ arg = args[i]
2229
+ if (arg,parent(arg)) in self._constant_locs:
2230
+ self._bytecode.append(self._constant_locs[(arg,parent(arg))])
2231
+ else:
2232
+ loc = len(self._constants)
2233
+ self._constants.append(arg)
2234
+ self._constant_locs[(arg,parent(arg))] = loc
2235
+ self._bytecode.append(loc)
2236
+ elif spec.parameters[i] == 'args':
2237
+ self._bytecode.append(args[i])
2238
+ elif spec.parameters[i] == 'code':
2239
+ self._bytecode.append(args[i])
2240
+ elif spec.parameters[i] == 'n_inputs':
2241
+ self._bytecode.append(args[i])
2242
+ n_inputs = args[i]
2243
+ elif spec.parameters[i] == 'n_outputs':
2244
+ self._bytecode.append(args[i])
2245
+ n_outputs = args[i]
2246
+ elif spec.parameters[i] == 'py_constants':
2247
+ arg = args[i]
2248
+ if arg in self._py_constant_locs:
2249
+ self._bytecode.append(self._py_constant_locs[arg])
2250
+ else:
2251
+ loc = len(self._py_constants)
2252
+ self._py_constants.append(arg)
2253
+ self._py_constant_locs[arg] = loc
2254
+ self._bytecode.append(loc)
2255
+ else:
2256
+ raise ValueError
2257
+
2258
+ self._stack_cur_size -= n_inputs
2259
+ self._stack_cur_size += n_outputs
2260
+ self._stack_max_size = max(self._stack_max_size, self._stack_cur_size)
2261
+
2262
+ def get_metadata(self):
2263
+ r"""
2264
+ Return the interpreter metadata being used by the current :class:`InstructionStream`.
2265
+
2266
+ The code generator sometimes uses this to decide which code
2267
+ to generate.
2268
+
2269
+ EXAMPLES::
2270
+
2271
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2272
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2273
+ sage: from sage.ext.fast_callable import InstructionStream
2274
+ sage: instr_stream = InstructionStream(metadata, 1)
2275
+ sage: md = instr_stream.get_metadata()
2276
+ sage: type(md)
2277
+ <class 'sage.ext.fast_callable.InterpreterMetadata'>
2278
+ """
2279
+ return self._metadata
2280
+
2281
+ def current_op_list(self):
2282
+ r"""
2283
+ Return the list of instructions that have been added to this
2284
+ :class:`InstructionStream` so far.
2285
+
2286
+ It's OK to call this, then add more instructions.
2287
+
2288
+ EXAMPLES::
2289
+
2290
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2291
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2292
+ sage: from sage.ext.fast_callable import InstructionStream
2293
+ sage: instr_stream = InstructionStream(metadata, 1)
2294
+ sage: instr_stream.instr('load_arg', 0)
2295
+ sage: instr_stream.instr('py_call', math.sin, 1)
2296
+ sage: instr_stream.instr('abs')
2297
+ sage: instr_stream.instr('return')
2298
+ sage: instr_stream.current_op_list()
2299
+ [('load_arg', 0), ('py_call', <built-in function sin>, 1), 'abs', 'return']
2300
+ """
2301
+ return op_list(self.get_current(), self._metadata)
2302
+
2303
+ def get_current(self):
2304
+ r"""
2305
+ Return the current state of the :class:`InstructionStream`, as a dictionary
2306
+ suitable for passing to a wrapper class.
2307
+
2308
+ NOTE: The dictionary includes internal data structures of the
2309
+ :class:`InstructionStream`; you must not modify it.
2310
+
2311
+ EXAMPLES::
2312
+
2313
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2314
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2315
+ sage: from sage.ext.fast_callable import InstructionStream
2316
+ sage: instr_stream = InstructionStream(metadata, 1)
2317
+ sage: instr_stream.get_current()
2318
+ {'args': 1,
2319
+ 'code': [],
2320
+ 'constants': [],
2321
+ 'domain': None,
2322
+ 'py_constants': [],
2323
+ 'stack': 0}
2324
+ sage: instr_stream.instr('load_arg', 0)
2325
+ sage: instr_stream.instr('py_call', math.sin, 1)
2326
+ sage: instr_stream.instr('abs')
2327
+ sage: instr_stream.instr('return')
2328
+ sage: instr_stream.current_op_list()
2329
+ [('load_arg', 0), ('py_call', <built-in function sin>, 1), 'abs', 'return']
2330
+ sage: instr_stream.get_current()
2331
+ {'args': 1,
2332
+ 'code': [0, 0, 3, 0, 1, 12, 2],
2333
+ 'constants': [],
2334
+ 'domain': None,
2335
+ 'py_constants': [<built-in function sin>],
2336
+ 'stack': 1}
2337
+ """
2338
+ d = {'args': self._n_args,
2339
+ 'constants': self._constants,
2340
+ 'py_constants': self._py_constants,
2341
+ 'stack': self._stack_max_size,
2342
+ 'code': self._bytecode,
2343
+ 'domain': self._domain}
2344
+ return d
2345
+
2346
+
2347
+ cdef class InterpreterMetadata():
2348
+ r"""
2349
+ The interpreter metadata for a :func:`fast_callable` interpreter.
2350
+
2351
+ Currently consists of a dictionary mapping instruction names to
2352
+ (:class:`CompilerInstrSpec`, opcode) pairs, a list mapping opcodes to
2353
+ (instruction name, :class:`CompilerInstrSpec`) pairs, and a range of exponents
2354
+ for which the ``'ipow'`` instruction can be used. This range can be
2355
+ ``False`` (if the ``'ipow'`` instruction should never be used), a pair of
2356
+ two integers `(a, b)`, if ``'ipow'`` should be used for `a \le n \le b`, or
2357
+ ``True``, if ``'ipow'`` should always be used. When ``'ipow'`` cannot be
2358
+ used, then we fall back on calling :class:`IntegerPowerFunction`.
2359
+
2360
+ See the class docstring for :class:`CompilerInstrSpec` for more information.
2361
+
2362
+ NOTE: You must not modify the metadata.
2363
+ """
2364
+ cdef public dict by_opname
2365
+ cdef public list by_opcode
2366
+ cdef public ipow_range
2367
+
2368
+ def __init__(self, by_opname, by_opcode, ipow_range):
2369
+ r"""
2370
+ Initialize an InterpreterMetadata object.
2371
+
2372
+ EXAMPLES::
2373
+
2374
+ sage: from sage.ext.fast_callable import InterpreterMetadata
2375
+ sage: metadata = InterpreterMetadata(by_opname={'opname dict goes here': True},
2376
+ ....: by_opcode=['opcode list goes here'],
2377
+ ....: ipow_range=(2, 57))
2378
+ sage: metadata.by_opname
2379
+ {'opname dict goes here': True}
2380
+ sage: metadata.by_opcode
2381
+ ['opcode list goes here']
2382
+ sage: metadata.ipow_range
2383
+ (2, 57)
2384
+ """
2385
+ self.by_opname = by_opname
2386
+ self.by_opcode = by_opcode
2387
+ self.ipow_range = ipow_range
2388
+
2389
+
2390
+ class CompilerInstrSpec():
2391
+ r"""
2392
+ Describe a single instruction to the :func:`fast_callable` code generator.
2393
+
2394
+ An instruction has a number of stack inputs, a number of stack
2395
+ outputs, and a parameter list describing extra arguments that
2396
+ must be passed to the :meth:`InstructionStream.instr` method (that end up
2397
+ as extra words in the code).
2398
+
2399
+ The parameter list is a list of strings. Each string is one of
2400
+ the following:
2401
+
2402
+ - ``'args'`` -- the instruction argument refers to an input argument of the
2403
+ wrapper class; it is just appended to the code
2404
+
2405
+ - ``'constants'``, ``'py_constants'`` -- the instruction argument is a value; the
2406
+ value is added to the corresponding list (if it's not already there) and
2407
+ the index is appended to the code.
2408
+
2409
+ - ``'n_inputs'``, ``'n_outputs'`` -- the instruction actually takes a variable
2410
+ number of inputs or outputs (the ``n_inputs`` and ``n_outputs`` attributes of
2411
+ this instruction are ignored). The instruction argument specifies the
2412
+ number of inputs or outputs (respectively); it is just appended to the
2413
+ code.
2414
+ """
2415
+
2416
+ def __init__(self, n_inputs, n_outputs, parameters):
2417
+ r"""
2418
+ Initialize a :class:`CompilerInstrSpec`.
2419
+
2420
+ EXAMPLES::
2421
+
2422
+ sage: from sage.ext.fast_callable import CompilerInstrSpec
2423
+ sage: CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])
2424
+ CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])
2425
+ """
2426
+ self.n_inputs = n_inputs
2427
+ self.n_outputs = n_outputs
2428
+ self.parameters = parameters
2429
+
2430
+ def __repr__(self):
2431
+ r"""
2432
+ Give a string representation for this :class:`CompilerInstrSpec`.
2433
+
2434
+ EXAMPLES::
2435
+
2436
+ sage: from sage.ext.fast_callable import CompilerInstrSpec
2437
+ sage: v = CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])
2438
+ sage: v
2439
+ CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])
2440
+ sage: repr(v)
2441
+ "CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])"
2442
+ sage: v.__repr__()
2443
+ "CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])"
2444
+ """
2445
+ return "CompilerInstrSpec(%d, %d, %s)" % (self.n_inputs, self.n_outputs, self.parameters)
2446
+
2447
+
2448
+ def op_list(args, metadata):
2449
+ r"""
2450
+ Given a dictionary with the result of calling :meth:`get_current` on an
2451
+ :class:`InstructionStream`, and the corresponding interpreter metadata,
2452
+ return a list of the instructions, in a simple somewhat
2453
+ human-readable format.
2454
+
2455
+ For debugging only. (That is, it's probably not a good idea to
2456
+ try to programmatically manipulate the result of this function;
2457
+ the expected use is just to print the returned list to the
2458
+ screen.)
2459
+
2460
+ There's probably no reason to call this directly; if you
2461
+ have a wrapper object, call :func:`op_list` on it; if you have an
2462
+ :class:`InstructionStream` object, call :meth:`current_op_list` on it.
2463
+
2464
+ EXAMPLES::
2465
+
2466
+ sage: from sage.ext.interpreters.wrapper_el import metadata
2467
+ sage: from sage.ext.interpreters.wrapper_rdf import metadata # needs sage.modules
2468
+ sage: from sage.ext.fast_callable import InstructionStream, op_list
2469
+ sage: instr_stream = InstructionStream(metadata, 1)
2470
+ sage: instr_stream.instr('load_arg', 0)
2471
+ sage: instr_stream.instr('abs')
2472
+ sage: instr_stream.instr('return')
2473
+ sage: instr_stream.current_op_list()
2474
+ [('load_arg', 0), 'abs', 'return']
2475
+ sage: op_list(instr_stream.get_current(), metadata)
2476
+ [('load_arg', 0), 'abs', 'return']
2477
+ """
2478
+ ops = []
2479
+ code = args['code']
2480
+ while len(code):
2481
+ opcode = code[0]
2482
+ code = code[1:]
2483
+ (opname, instr) = metadata.by_opcode[opcode]
2484
+ if len(instr.parameters):
2485
+ op = [opname]
2486
+ for p in instr.parameters:
2487
+ p_loc = code[0]
2488
+ code = code[1:]
2489
+ if p in ('args', 'code', 'n_inputs', 'n_outputs'):
2490
+ op.append(p_loc)
2491
+ else:
2492
+ op.append(args[p][p_loc])
2493
+ ops.append(tuple(op))
2494
+ else:
2495
+ ops.append(opname)
2496
+ return ops
2497
+
2498
+
2499
+ cdef class Wrapper:
2500
+ r"""
2501
+ The parent class for all :func:`fast_callable` wrappers.
2502
+
2503
+ Implements shared behavior (currently only debugging).
2504
+ """
2505
+
2506
+ def __init__(self, args, metadata):
2507
+ r"""
2508
+ Initialize a Wrapper object.
2509
+
2510
+ EXAMPLES::
2511
+
2512
+ sage: # needs sage.symbolic
2513
+ sage: from sage.ext.fast_callable import ExpressionTreeBuilder, generate_code, InstructionStream
2514
+ sage: etb = ExpressionTreeBuilder('x')
2515
+ sage: x = etb.var('x')
2516
+ sage: expr = (x+pi) * (x+1)
2517
+ sage: from sage.ext.interpreters.wrapper_py import metadata, Wrapper_py
2518
+ sage: instr_stream = InstructionStream(metadata, 1)
2519
+ sage: generate_code(expr, instr_stream)
2520
+ sage: instr_stream.instr('return')
2521
+ sage: v = Wrapper_py(instr_stream.get_current())
2522
+ sage: v.get_orig_args()
2523
+ {'args': 1,
2524
+ 'code': [0, 0, 1, 0, 4, 0, 0, 1, 1, 4, 6, 2],
2525
+ 'constants': [pi, 1],
2526
+ 'domain': None,
2527
+ 'py_constants': [],
2528
+ 'stack': 3}
2529
+ sage: v.op_list()
2530
+ [('load_arg', 0), ('load_const', pi), 'add', ('load_arg', 0), ('load_const', 1), 'add', 'mul', 'return']
2531
+ """
2532
+
2533
+ # We only keep the original arguments for debugging (op_list(), etc.);
2534
+ # is it worth the memory cost? (Note that we may be holding on to
2535
+ # large objects that could otherwise be garbage collected, for
2536
+ # instance.)
2537
+ self._orig_args = args
2538
+ self._metadata = metadata
2539
+
2540
+ def get_orig_args(self):
2541
+ r"""
2542
+ Get the original arguments used when initializing this wrapper.
2543
+
2544
+ (Probably only useful when writing doctests.)
2545
+
2546
+ EXAMPLES::
2547
+
2548
+ sage: fast_callable(sin(x)/x, vars=[x], domain=RDF).get_orig_args() # needs sage.symbolic
2549
+ {'args': 1,
2550
+ 'code': [0, 0, 16, 0, 0, 8, 2],
2551
+ 'constants': [],
2552
+ 'domain': Real Double Field,
2553
+ 'py_constants': [],
2554
+ 'stack': 2}
2555
+ """
2556
+ return self._orig_args
2557
+
2558
+ def op_list(self):
2559
+ r"""
2560
+ Return the list of instructions in this wrapper.
2561
+
2562
+ EXAMPLES::
2563
+
2564
+ sage: fast_callable(cos(x) * x, vars=[x], domain=RDF).op_list() # needs sage.symbolic
2565
+ [('load_arg', 0), ('load_arg', 0), 'cos', 'mul', 'return']
2566
+ """
2567
+ return op_list(self._orig_args, self._metadata)
2568
+
2569
+ def python_calls(self):
2570
+ r"""
2571
+ List the Python functions that are called in this wrapper.
2572
+
2573
+ (Python function calls are slow, so ideally this list would
2574
+ be empty. If it is not empty, then perhaps there is an
2575
+ optimization opportunity where a Sage developer could speed
2576
+ this up by adding a new instruction to the interpreter.)
2577
+
2578
+ EXAMPLES::
2579
+
2580
+ sage: fast_callable(abs(sin(x)), vars=[x], domain=RDF).python_calls() # needs sage.symbolic
2581
+ []
2582
+ sage: fast_callable(abs(sin(factorial(x))), vars=[x]).python_calls() # needs sage.symbolic
2583
+ [factorial, sin]
2584
+ """
2585
+ ops = self.op_list()
2586
+ py_calls = []
2587
+ for op in ops:
2588
+ if isinstance(op, tuple) and op[0] == 'py_call':
2589
+ py_calls.append(op[1])
2590
+ return py_calls
2591
+
2592
+
2593
+ class FastCallableFloatWrapper:
2594
+ r"""
2595
+ A class to alter the return types of the fast-callable functions.
2596
+
2597
+ When applying numerical routines (including plotting) to symbolic
2598
+ expressions and functions, we generally first convert them to a
2599
+ faster form with :func:`fast_callable`. That function takes a
2600
+ ``domain`` parameter that forces the end (and all intermediate)
2601
+ results of evaluation to a specific type. Though usually always
2602
+ want the end result to be of type :class:`float`, correctly choosing
2603
+ the ``domain`` presents some problems:
2604
+
2605
+ * :class:`float` is a bad choice because it's common for real
2606
+ functions to have complex terms in them. Moreover precision
2607
+ issues can produce terms like ``1.0 + 1e-12*I`` that are hard
2608
+ to avoid if calling ``real()`` on everything is infeasible.
2609
+
2610
+ * :class:`complex` has essentially the same problem as :class:`float`.
2611
+ There are several symbolic functions like :func:`min_symbolic`,
2612
+ :func:`max_symbolic`, and :func:`floor` that are unable to
2613
+ operate on complex numbers.
2614
+
2615
+ * ``None`` leaves the types of the inputs/outputs alone, but due
2616
+ to the lack of a specialized interpreter, slows down evaluation
2617
+ by an unacceptable amount.
2618
+
2619
+ * ``CDF`` has none of the other issues, because ``CDF`` has its
2620
+ own specialized interpreter, a lexicographic ordering (for
2621
+ min/max), and supports :func:`floor`. However, most numerical
2622
+ functions cannot handle complex numbers, so using ``CDF``
2623
+ would require us to wrap every evaluation in a
2624
+ ``CDF``-to-:class:`float` conversion routine. That would slow
2625
+ things down less than a domain of ``None`` would, but is
2626
+ unattractive mainly because of how invasive it would be to
2627
+ "fix" the output everywhere.
2628
+
2629
+ Creating a new fast-callable interpreter that has different input
2630
+ and output types solves most of the problems with a ``CDF``
2631
+ domain, but :func:`fast_callable` and the interpreter classes in
2632
+ :mod:`sage.ext.interpreters` are not really written with that in
2633
+ mind. The ``domain`` parameter to :func:`fast_callable`, for
2634
+ example, is expecting a single Sage ring that corresponds to one
2635
+ interpreter. You can make it accept, for example, a string like
2636
+ "CDF-to-float", but the hacks required to make that work feel
2637
+ wrong.
2638
+
2639
+ Thus we arrive at this solution: a class to wrap the result of
2640
+ :func:`fast_callable`. Whenever we need to support intermediate
2641
+ complex terms in a numerical routine, we can set ``domain=CDF``
2642
+ while creating its fast-callable incarnation, and then wrap the
2643
+ result in this class. The :meth:`__call__` method of this class then
2644
+ ensures that the ``CDF`` output is converted to a :class:`float` if
2645
+ its imaginary part is within an acceptable tolerance.
2646
+
2647
+ EXAMPLES:
2648
+
2649
+ An error is thrown if the answer is complex::
2650
+
2651
+ sage: # needs sage.symbolic
2652
+ sage: from sage.ext.fast_callable import FastCallableFloatWrapper
2653
+ sage: f = sqrt(x)
2654
+ sage: ff = fast_callable(f, vars=[x], domain=CDF)
2655
+ sage: fff = FastCallableFloatWrapper(ff, imag_tol=1e-8)
2656
+ sage: fff(1)
2657
+ 1.0
2658
+ sage: fff(-1)
2659
+ Traceback (most recent call last):
2660
+ ...
2661
+ ValueError: complex fast-callable function result
2662
+ 1.0*I for arguments (-1,)
2663
+ """
2664
+ def __init__(self, ff, imag_tol):
2665
+ r"""
2666
+ Construct a :class:`FastCallableFloatWrapper`.
2667
+
2668
+ INPUT:
2669
+
2670
+ - ``ff`` -- a fast-callable wrapper over ``CDF``; an instance of
2671
+ :class:`sage.ext.interpreters.Wrapper_cdf`, usually constructed
2672
+ with :func:`fast_callable`.
2673
+
2674
+ - ``imag_tol`` -- float; how big of an imaginary part we're willing
2675
+ to ignore before raising an error
2676
+
2677
+ OUTPUT:
2678
+
2679
+ An instance of :class:`FastCallableFloatWrapper` that can be
2680
+ called just like ``ff``, but that always returns a :class:`float`
2681
+ if no error is raised. A :exc:`ValueError` is raised if the
2682
+ imaginary part of the result exceeds ``imag_tol``.
2683
+
2684
+ EXAMPLES:
2685
+
2686
+ The wrapper will ignore an imaginary part smaller in magnitude
2687
+ than ``imag_tol``, but not one larger::
2688
+
2689
+ sage: # needs sage.symbolic
2690
+ sage: from sage.ext.fast_callable import FastCallableFloatWrapper
2691
+ sage: f = x
2692
+ sage: ff = fast_callable(f, vars=[x], domain=CDF)
2693
+ sage: fff = FastCallableFloatWrapper(ff, imag_tol=1e-8)
2694
+ sage: fff(I*1e-9)
2695
+ 0.0
2696
+ sage: fff = FastCallableFloatWrapper(ff, imag_tol=1e-12)
2697
+ sage: fff(I*1e-9)
2698
+ Traceback (most recent call last):
2699
+ ...
2700
+ ValueError: complex fast-callable function result 1e-09*I for
2701
+ arguments (1.00000000000000e-9*I,)
2702
+ """
2703
+ self._ff = ff
2704
+ self._imag_tol = imag_tol
2705
+
2706
+ def __call__(self, *args):
2707
+ r"""
2708
+ Evaluate the underlying fast-callable and convert the result to :class:`float`.
2709
+
2710
+ TESTS:
2711
+
2712
+ Evaluation either returns a :class:`float`, or raises a :exc:`ValueError`::
2713
+
2714
+ sage: # needs sage.symbolic
2715
+ sage: from sage.ext.fast_callable import FastCallableFloatWrapper
2716
+ sage: f = x
2717
+ sage: ff = fast_callable(f, vars=[x], domain=CDF)
2718
+ sage: fff = FastCallableFloatWrapper(ff, imag_tol=0.1)
2719
+ sage: try:
2720
+ ....: result = fff(CDF.random_element())
2721
+ ....: except ValueError:
2722
+ ....: result = float(0)
2723
+ sage: type(result) is float
2724
+ True
2725
+ """
2726
+ z = self._ff(*args)
2727
+
2728
+ if abs(z.imag()) < self._imag_tol:
2729
+ return float(z.real())
2730
+ elif isnan(z.real()) and isnan(z.imag()):
2731
+ # A fast-callable with domain=float or domain=RDF will
2732
+ # return NaN if that's what the underlying function itself
2733
+ # returns. When performing the same computation over CDF,
2734
+ # however, we get something special; witness:
2735
+ #
2736
+ # sage: RDF(0)*math.inf
2737
+ # NaN
2738
+ # sage: CDF(0)*math.inf
2739
+ # NaN + NaN*I
2740
+ #
2741
+ # Thus for backwards-compatibility, we handle this special
2742
+ # case to return NaN to anyone expecting it.
2743
+ return nan
2744
+ else:
2745
+ raise ValueError(f"complex fast-callable function result {z} " +
2746
+ f"for arguments {args}")