snappy 3.3__cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_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 (541) hide show
  1. snappy/CyOpenGL.cpython-310-aarch64-linux-gnu.so +0 -0
  2. snappy/SnapPy.cpython-310-aarch64-linux-gnu.so +0 -0
  3. snappy/SnapPy.ico +0 -0
  4. snappy/SnapPy.png +0 -0
  5. snappy/SnapPyHP.cpython-310-aarch64-linux-gnu.so +0 -0
  6. snappy/__init__.py +534 -0
  7. snappy/app.py +604 -0
  8. snappy/app_menus.py +372 -0
  9. snappy/browser.py +998 -0
  10. snappy/cache.py +25 -0
  11. snappy/canonical.py +249 -0
  12. snappy/cusps/__init__.py +280 -0
  13. snappy/cusps/cusp_area_matrix.py +98 -0
  14. snappy/cusps/cusp_areas_from_matrix.py +96 -0
  15. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  16. snappy/cusps/short_slopes_for_cusp.py +217 -0
  17. snappy/cusps/test.py +22 -0
  18. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  19. snappy/database.py +454 -0
  20. snappy/db_utilities.py +79 -0
  21. snappy/decorated_isosig.py +717 -0
  22. snappy/dev/__init__.py +0 -0
  23. snappy/dev/extended_ptolemy/__init__.py +8 -0
  24. snappy/dev/extended_ptolemy/closed.py +106 -0
  25. snappy/dev/extended_ptolemy/complexVolumesClosed.py +149 -0
  26. snappy/dev/extended_ptolemy/direct.py +42 -0
  27. snappy/dev/extended_ptolemy/extended.py +406 -0
  28. snappy/dev/extended_ptolemy/giac_helper.py +43 -0
  29. snappy/dev/extended_ptolemy/giac_rur.py +129 -0
  30. snappy/dev/extended_ptolemy/gluing.py +46 -0
  31. snappy/dev/extended_ptolemy/phc_wrapper.py +220 -0
  32. snappy/dev/extended_ptolemy/printMatrices.py +70 -0
  33. snappy/dev/vericlosed/__init__.py +1 -0
  34. snappy/dev/vericlosed/computeApproxHyperbolicStructureNew.py +159 -0
  35. snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +90 -0
  36. snappy/dev/vericlosed/computeVerifiedHyperbolicStructure.py +111 -0
  37. snappy/dev/vericlosed/gimbalLoopFinder.py +130 -0
  38. snappy/dev/vericlosed/hyperbolicStructure.py +313 -0
  39. snappy/dev/vericlosed/krawczykCertifiedEdgeLengthsEngine.py +165 -0
  40. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +122 -0
  41. snappy/dev/vericlosed/orb/__init__.py +1 -0
  42. snappy/dev/vericlosed/orb/orb_solution_for_snappea_finite_triangulation_mac +0 -0
  43. snappy/dev/vericlosed/parseVertexGramMatrixFile.py +47 -0
  44. snappy/dev/vericlosed/polishApproxHyperbolicStructure.py +61 -0
  45. snappy/dev/vericlosed/test.py +54 -0
  46. snappy/dev/vericlosed/truncatedComplex.py +176 -0
  47. snappy/dev/vericlosed/verificationError.py +58 -0
  48. snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +177 -0
  49. snappy/doc/_images/SnapPy-196.png +0 -0
  50. snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
  51. snappy/doc/_images/m125_paper_plane.jpg +0 -0
  52. snappy/doc/_images/mac.png +0 -0
  53. snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
  54. snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
  55. snappy/doc/_images/plink-action.png +0 -0
  56. snappy/doc/_images/ubuntu.png +0 -0
  57. snappy/doc/_images/win7.png +0 -0
  58. snappy/doc/_sources/additional_classes.rst.txt +40 -0
  59. snappy/doc/_sources/bugs.rst.txt +14 -0
  60. snappy/doc/_sources/censuses.rst.txt +52 -0
  61. snappy/doc/_sources/credits.rst.txt +81 -0
  62. snappy/doc/_sources/development.rst.txt +261 -0
  63. snappy/doc/_sources/index.rst.txt +215 -0
  64. snappy/doc/_sources/installing.rst.txt +249 -0
  65. snappy/doc/_sources/manifold.rst.txt +6 -0
  66. snappy/doc/_sources/manifoldhp.rst.txt +46 -0
  67. snappy/doc/_sources/news.rst.txt +425 -0
  68. snappy/doc/_sources/other.rst.txt +25 -0
  69. snappy/doc/_sources/platonic_census.rst.txt +20 -0
  70. snappy/doc/_sources/plink.rst.txt +102 -0
  71. snappy/doc/_sources/ptolemy.rst.txt +66 -0
  72. snappy/doc/_sources/ptolemy_classes.rst.txt +42 -0
  73. snappy/doc/_sources/ptolemy_examples1.rst.txt +298 -0
  74. snappy/doc/_sources/ptolemy_examples2.rst.txt +363 -0
  75. snappy/doc/_sources/ptolemy_examples3.rst.txt +301 -0
  76. snappy/doc/_sources/ptolemy_examples4.rst.txt +61 -0
  77. snappy/doc/_sources/ptolemy_prelim.rst.txt +105 -0
  78. snappy/doc/_sources/screenshots.rst.txt +21 -0
  79. snappy/doc/_sources/snap.rst.txt +87 -0
  80. snappy/doc/_sources/snappy.rst.txt +28 -0
  81. snappy/doc/_sources/spherogram.rst.txt +103 -0
  82. snappy/doc/_sources/todo.rst.txt +47 -0
  83. snappy/doc/_sources/triangulation.rst.txt +11 -0
  84. snappy/doc/_sources/tutorial.rst.txt +49 -0
  85. snappy/doc/_sources/verify.rst.txt +210 -0
  86. snappy/doc/_sources/verify_internals.rst.txt +79 -0
  87. snappy/doc/_static/SnapPy-horizontal-128.png +0 -0
  88. snappy/doc/_static/SnapPy.ico +0 -0
  89. snappy/doc/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  90. snappy/doc/_static/basic.css +906 -0
  91. snappy/doc/_static/css/badge_only.css +1 -0
  92. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  93. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  94. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  95. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  96. snappy/doc/_static/css/fonts/fontawesome-webfont.eot +0 -0
  97. snappy/doc/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  98. snappy/doc/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  99. snappy/doc/_static/css/fonts/fontawesome-webfont.woff +0 -0
  100. snappy/doc/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  101. snappy/doc/_static/css/fonts/lato-bold-italic.woff +0 -0
  102. snappy/doc/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  103. snappy/doc/_static/css/fonts/lato-bold.woff +0 -0
  104. snappy/doc/_static/css/fonts/lato-bold.woff2 +0 -0
  105. snappy/doc/_static/css/fonts/lato-normal-italic.woff +0 -0
  106. snappy/doc/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  107. snappy/doc/_static/css/fonts/lato-normal.woff +0 -0
  108. snappy/doc/_static/css/fonts/lato-normal.woff2 +0 -0
  109. snappy/doc/_static/css/theme.css +4 -0
  110. snappy/doc/_static/doctools.js +149 -0
  111. snappy/doc/_static/documentation_options.js +13 -0
  112. snappy/doc/_static/file.png +0 -0
  113. snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
  114. snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
  115. snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
  116. snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
  117. snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  118. snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  119. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  120. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  121. snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
  122. snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
  123. snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
  124. snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
  125. snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
  126. snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
  127. snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
  128. snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
  129. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  130. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  131. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  132. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  133. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  134. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  135. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  136. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  137. snappy/doc/_static/jquery.js +2 -0
  138. snappy/doc/_static/js/badge_only.js +1 -0
  139. snappy/doc/_static/js/theme.js +1 -0
  140. snappy/doc/_static/js/versions.js +228 -0
  141. snappy/doc/_static/language_data.js +192 -0
  142. snappy/doc/_static/minus.png +0 -0
  143. snappy/doc/_static/plus.png +0 -0
  144. snappy/doc/_static/pygments.css +75 -0
  145. snappy/doc/_static/searchtools.js +635 -0
  146. snappy/doc/_static/snappy_furo.css +33 -0
  147. snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -0
  148. snappy/doc/_static/sphinx_highlight.js +154 -0
  149. snappy/doc/additional_classes.html +1500 -0
  150. snappy/doc/bugs.html +132 -0
  151. snappy/doc/censuses.html +453 -0
  152. snappy/doc/credits.html +184 -0
  153. snappy/doc/development.html +385 -0
  154. snappy/doc/doc-latest/additional_classes.html +1500 -0
  155. snappy/doc/doc-latest/bugs.html +132 -0
  156. snappy/doc/doc-latest/censuses.html +453 -0
  157. snappy/doc/doc-latest/credits.html +184 -0
  158. snappy/doc/doc-latest/development.html +385 -0
  159. snappy/doc/doc-latest/genindex.html +1349 -0
  160. snappy/doc/doc-latest/index.html +287 -0
  161. snappy/doc/doc-latest/installing.html +346 -0
  162. snappy/doc/doc-latest/manifold.html +3632 -0
  163. snappy/doc/doc-latest/manifoldhp.html +180 -0
  164. snappy/doc/doc-latest/news.html +438 -0
  165. snappy/doc/doc-latest/objects.inv +0 -0
  166. snappy/doc/doc-latest/other.html +160 -0
  167. snappy/doc/doc-latest/platonic_census.html +376 -0
  168. snappy/doc/doc-latest/plink.html +210 -0
  169. snappy/doc/doc-latest/ptolemy.html +253 -0
  170. snappy/doc/doc-latest/ptolemy_classes.html +1144 -0
  171. snappy/doc/doc-latest/ptolemy_examples1.html +409 -0
  172. snappy/doc/doc-latest/ptolemy_examples2.html +471 -0
  173. snappy/doc/doc-latest/ptolemy_examples3.html +414 -0
  174. snappy/doc/doc-latest/ptolemy_examples4.html +195 -0
  175. snappy/doc/doc-latest/ptolemy_prelim.html +248 -0
  176. snappy/doc/doc-latest/py-modindex.html +165 -0
  177. snappy/doc/doc-latest/screenshots.html +141 -0
  178. snappy/doc/doc-latest/search.html +135 -0
  179. snappy/doc/doc-latest/searchindex.js +1 -0
  180. snappy/doc/doc-latest/snap.html +202 -0
  181. snappy/doc/doc-latest/snappy.html +181 -0
  182. snappy/doc/doc-latest/spherogram.html +1346 -0
  183. snappy/doc/doc-latest/todo.html +166 -0
  184. snappy/doc/doc-latest/triangulation.html +1676 -0
  185. snappy/doc/doc-latest/tutorial.html +159 -0
  186. snappy/doc/doc-latest/verify.html +330 -0
  187. snappy/doc/doc-latest/verify_internals.html +1235 -0
  188. snappy/doc/genindex.html +1349 -0
  189. snappy/doc/index.html +287 -0
  190. snappy/doc/installing.html +346 -0
  191. snappy/doc/manifold.html +3632 -0
  192. snappy/doc/manifoldhp.html +180 -0
  193. snappy/doc/news.html +438 -0
  194. snappy/doc/objects.inv +0 -0
  195. snappy/doc/other.html +160 -0
  196. snappy/doc/platonic_census.html +376 -0
  197. snappy/doc/plink.html +210 -0
  198. snappy/doc/ptolemy.html +253 -0
  199. snappy/doc/ptolemy_classes.html +1144 -0
  200. snappy/doc/ptolemy_examples1.html +409 -0
  201. snappy/doc/ptolemy_examples2.html +471 -0
  202. snappy/doc/ptolemy_examples3.html +414 -0
  203. snappy/doc/ptolemy_examples4.html +195 -0
  204. snappy/doc/ptolemy_prelim.html +248 -0
  205. snappy/doc/py-modindex.html +165 -0
  206. snappy/doc/screenshots.html +141 -0
  207. snappy/doc/search.html +135 -0
  208. snappy/doc/searchindex.js +1 -0
  209. snappy/doc/snap.html +202 -0
  210. snappy/doc/snappy.html +181 -0
  211. snappy/doc/spherogram.html +1346 -0
  212. snappy/doc/todo.html +166 -0
  213. snappy/doc/triangulation.html +1676 -0
  214. snappy/doc/tutorial.html +159 -0
  215. snappy/doc/verify.html +330 -0
  216. snappy/doc/verify_internals.html +1235 -0
  217. snappy/drilling/__init__.py +456 -0
  218. snappy/drilling/barycentric.py +103 -0
  219. snappy/drilling/constants.py +5 -0
  220. snappy/drilling/crush.py +270 -0
  221. snappy/drilling/cusps.py +125 -0
  222. snappy/drilling/debug.py +242 -0
  223. snappy/drilling/epsilons.py +6 -0
  224. snappy/drilling/exceptions.py +55 -0
  225. snappy/drilling/moves.py +620 -0
  226. snappy/drilling/peripheral_curves.py +210 -0
  227. snappy/drilling/perturb.py +188 -0
  228. snappy/drilling/shorten.py +36 -0
  229. snappy/drilling/subdivide.py +274 -0
  230. snappy/drilling/test.py +23 -0
  231. snappy/drilling/test_cases.py +132 -0
  232. snappy/drilling/tracing.py +351 -0
  233. snappy/exceptions.py +26 -0
  234. snappy/export_stl.py +120 -0
  235. snappy/exterior_to_link/__init__.py +2 -0
  236. snappy/exterior_to_link/barycentric_geometry.py +463 -0
  237. snappy/exterior_to_link/exceptions.py +6 -0
  238. snappy/exterior_to_link/geodesic_map.json +14408 -0
  239. snappy/exterior_to_link/hyp_utils.py +112 -0
  240. snappy/exterior_to_link/link_projection.py +323 -0
  241. snappy/exterior_to_link/main.py +198 -0
  242. snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
  243. snappy/exterior_to_link/mcomplex_with_link.py +687 -0
  244. snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
  245. snappy/exterior_to_link/pl_utils.py +491 -0
  246. snappy/exterior_to_link/put_in_S3.py +156 -0
  247. snappy/exterior_to_link/rational_linear_algebra.py +130 -0
  248. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
  249. snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
  250. snappy/exterior_to_link/stored_moves.py +475 -0
  251. snappy/exterior_to_link/test.py +31 -0
  252. snappy/filedialog.py +28 -0
  253. snappy/geometric_structure/__init__.py +212 -0
  254. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  255. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +691 -0
  256. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +480 -0
  257. snappy/geometric_structure/cusp_neighborhood/exceptions.py +41 -0
  258. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +294 -0
  259. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +156 -0
  260. snappy/geometric_structure/cusp_neighborhood/vertices.py +35 -0
  261. snappy/geometric_structure/geodesic/__init__.py +0 -0
  262. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  263. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  264. snappy/geometric_structure/geodesic/canonical_representatives.py +52 -0
  265. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  266. snappy/geometric_structure/geodesic/constants.py +6 -0
  267. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  268. snappy/geometric_structure/geodesic/fixed_points.py +106 -0
  269. snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
  270. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  271. snappy/geometric_structure/geodesic/line.py +30 -0
  272. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  273. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +128 -0
  274. snappy/geometric_structure/test.py +22 -0
  275. snappy/gui.py +121 -0
  276. snappy/horoviewer.py +443 -0
  277. snappy/hyperboloid/__init__.py +212 -0
  278. snappy/hyperboloid/distances.py +259 -0
  279. snappy/hyperboloid/horoball.py +19 -0
  280. snappy/hyperboloid/line.py +35 -0
  281. snappy/hyperboloid/point.py +9 -0
  282. snappy/hyperboloid/triangle.py +29 -0
  283. snappy/info_icon.gif +0 -0
  284. snappy/infowindow.py +65 -0
  285. snappy/isometry_signature.py +389 -0
  286. snappy/len_spec/__init__.py +609 -0
  287. snappy/len_spec/geodesic_info.py +129 -0
  288. snappy/len_spec/geodesic_key_info_dict.py +116 -0
  289. snappy/len_spec/geodesic_piece.py +146 -0
  290. snappy/len_spec/geometric_structure.py +182 -0
  291. snappy/len_spec/geometry.py +136 -0
  292. snappy/len_spec/length_spectrum_geodesic_info.py +185 -0
  293. snappy/len_spec/spine.py +128 -0
  294. snappy/len_spec/test.py +24 -0
  295. snappy/len_spec/test_cases.py +69 -0
  296. snappy/len_spec/tile.py +276 -0
  297. snappy/len_spec/word.py +86 -0
  298. snappy/manifolds/HTWKnots/alternating.gz +0 -0
  299. snappy/manifolds/HTWKnots/nonalternating.gz +0 -0
  300. snappy/manifolds/__init__.py +3 -0
  301. snappy/margulis/__init__.py +332 -0
  302. snappy/margulis/cusp_neighborhood_neighborhood.py +66 -0
  303. snappy/margulis/geodesic_neighborhood.py +152 -0
  304. snappy/margulis/margulis_info.py +21 -0
  305. snappy/margulis/mu_from_neighborhood_pair.py +175 -0
  306. snappy/margulis/neighborhood.py +29 -0
  307. snappy/margulis/test.py +22 -0
  308. snappy/math_basics.py +187 -0
  309. snappy/matrix.py +525 -0
  310. snappy/number.py +657 -0
  311. snappy/numeric_output_checker.py +345 -0
  312. snappy/pari.py +41 -0
  313. snappy/phone_home.py +57 -0
  314. snappy/polyviewer.py +259 -0
  315. snappy/ptolemy/__init__.py +17 -0
  316. snappy/ptolemy/component.py +103 -0
  317. snappy/ptolemy/coordinates.py +2290 -0
  318. snappy/ptolemy/fieldExtensions.py +153 -0
  319. snappy/ptolemy/findLoops.py +473 -0
  320. snappy/ptolemy/geometricRep.py +59 -0
  321. snappy/ptolemy/homology.py +165 -0
  322. snappy/ptolemy/magma/default.magma_template +229 -0
  323. snappy/ptolemy/magma/radicalsOfPrimaryDecomposition.magma_template +79 -0
  324. snappy/ptolemy/manifoldMethods.py +395 -0
  325. snappy/ptolemy/matrix.py +350 -0
  326. snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +113 -0
  327. snappy/ptolemy/polynomial.py +856 -0
  328. snappy/ptolemy/processComponents.py +173 -0
  329. snappy/ptolemy/processFileBase.py +247 -0
  330. snappy/ptolemy/processFileDispatch.py +46 -0
  331. snappy/ptolemy/processMagmaFile.py +392 -0
  332. snappy/ptolemy/processRurFile.py +150 -0
  333. snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +102 -0
  334. snappy/ptolemy/ptolemyObstructionClass.py +64 -0
  335. snappy/ptolemy/ptolemyVariety.py +995 -0
  336. snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +140 -0
  337. snappy/ptolemy/reginaWrapper.py +698 -0
  338. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  339. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  340. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  341. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  342. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  343. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  344. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  345. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  346. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  347. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  348. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c0.magma_out.bz2 +0 -0
  349. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  350. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  351. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c1.magma_out.bz2 +0 -0
  352. snappy/ptolemy/rur.py +545 -0
  353. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +277 -0
  354. snappy/ptolemy/test.py +1126 -0
  355. snappy/ptolemy/testing_files/3_1__sl2_c0.magma_out.bz2 +0 -0
  356. snappy/ptolemy/testing_files/3_1__sl2_c1.magma_out.bz2 +0 -0
  357. snappy/ptolemy/testing_files/4_1__sl2_c0.magma_out.bz2 +0 -0
  358. snappy/ptolemy/testing_files/4_1__sl2_c1.magma_out.bz2 +0 -0
  359. snappy/ptolemy/testing_files/4_1__sl3_c0.magma_out.bz2 +0 -0
  360. snappy/ptolemy/testing_files/4_1__sl4_c0.magma_out.bz2 +0 -0
  361. snappy/ptolemy/testing_files/4_1__sl4_c1.magma_out.bz2 +0 -0
  362. snappy/ptolemy/testing_files/5_2__sl2_c0.magma_out.bz2 +0 -0
  363. snappy/ptolemy/testing_files/5_2__sl2_c1.magma_out.bz2 +0 -0
  364. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  365. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  366. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  367. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  368. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  369. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  370. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  371. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  372. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c0.magma_out +95 -0
  373. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c1.magma_out +95 -0
  374. snappy/ptolemy/testing_files/m015__sl3_c0.magma_out.bz2 +0 -0
  375. snappy/ptolemy/testing_files/m135__sl2_c0.magma_out.bz2 +0 -0
  376. snappy/ptolemy/testing_files/m135__sl2_c1.magma_out.bz2 +0 -0
  377. snappy/ptolemy/testing_files/m135__sl2_c2.magma_out.bz2 +0 -0
  378. snappy/ptolemy/testing_files/m135__sl2_c3.magma_out.bz2 +0 -0
  379. snappy/ptolemy/testing_files/m135__sl2_c4.magma_out.bz2 +0 -0
  380. snappy/ptolemy/testing_files/m135__sl2_c5.magma_out.bz2 +0 -0
  381. snappy/ptolemy/testing_files/m135__sl2_c6.magma_out.bz2 +0 -0
  382. snappy/ptolemy/testing_files/m135__sl2_c7.magma_out.bz2 +0 -0
  383. snappy/ptolemy/testing_files/s000__sl2_c0.magma_out.bz2 +0 -0
  384. snappy/ptolemy/testing_files/s000__sl2_c1.magma_out.bz2 +0 -0
  385. snappy/ptolemy/testing_files/t00000__sl2_c0.magma_out.bz2 +0 -0
  386. snappy/ptolemy/testing_files/t00000__sl2_c1.magma_out.bz2 +0 -0
  387. snappy/ptolemy/testing_files/v0000__sl2_c0.magma_out.bz2 +0 -0
  388. snappy/ptolemy/testing_files/v0000__sl2_c1.magma_out.bz2 +0 -0
  389. snappy/ptolemy/testing_files/v0000__sl2_c2.magma_out.bz2 +0 -0
  390. snappy/ptolemy/testing_files/v0000__sl2_c3.magma_out.bz2 +0 -0
  391. snappy/ptolemy/testing_files_generalized/m003__sl2_c0.magma_out.bz2 +0 -0
  392. snappy/ptolemy/testing_files_generalized/m003__sl2_c1.magma_out.bz2 +0 -0
  393. snappy/ptolemy/testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  394. snappy/ptolemy/testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  395. snappy/ptolemy/testing_files_generalized/m004__sl2_c0.magma_out.bz2 +0 -0
  396. snappy/ptolemy/testing_files_generalized/m004__sl2_c1.magma_out.bz2 +0 -0
  397. snappy/ptolemy/testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  398. snappy/ptolemy/testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  399. snappy/ptolemy/testing_files_rur/m052__sl3_c0.rur.bz2 +0 -0
  400. snappy/ptolemy/utilities.py +236 -0
  401. snappy/raytracing/__init__.py +64 -0
  402. snappy/raytracing/additional_horospheres.py +64 -0
  403. snappy/raytracing/additional_len_spec_choices.py +63 -0
  404. snappy/raytracing/cohomology_fractal.py +197 -0
  405. snappy/raytracing/eyeball.py +124 -0
  406. snappy/raytracing/finite_raytracing_data.py +237 -0
  407. snappy/raytracing/finite_viewer.py +590 -0
  408. snappy/raytracing/geodesic_tube_info.py +174 -0
  409. snappy/raytracing/geodesics.py +246 -0
  410. snappy/raytracing/geodesics_window.py +258 -0
  411. snappy/raytracing/gui_utilities.py +293 -0
  412. snappy/raytracing/hyperboloid_navigation.py +556 -0
  413. snappy/raytracing/hyperboloid_utilities.py +234 -0
  414. snappy/raytracing/ideal_raytracing_data.py +592 -0
  415. snappy/raytracing/inside_viewer.py +974 -0
  416. snappy/raytracing/pack.py +22 -0
  417. snappy/raytracing/raytracing_data.py +126 -0
  418. snappy/raytracing/raytracing_view.py +454 -0
  419. snappy/raytracing/shaders/Eye.png +0 -0
  420. snappy/raytracing/shaders/NonGeometric.png +0 -0
  421. snappy/raytracing/shaders/__init__.py +101 -0
  422. snappy/raytracing/shaders/fragment.glsl +1744 -0
  423. snappy/raytracing/test.py +29 -0
  424. snappy/raytracing/tooltip.py +146 -0
  425. snappy/raytracing/upper_halfspace_utilities.py +98 -0
  426. snappy/raytracing/view_scale_controller.py +98 -0
  427. snappy/raytracing/zoom_slider/__init__.py +263 -0
  428. snappy/raytracing/zoom_slider/inward.png +0 -0
  429. snappy/raytracing/zoom_slider/inward18.png +0 -0
  430. snappy/raytracing/zoom_slider/outward.png +0 -0
  431. snappy/raytracing/zoom_slider/outward18.png +0 -0
  432. snappy/raytracing/zoom_slider/test.py +20 -0
  433. snappy/sage_helper.py +119 -0
  434. snappy/settings.py +407 -0
  435. snappy/shell.py +53 -0
  436. snappy/snap/__init__.py +117 -0
  437. snappy/snap/character_varieties.py +375 -0
  438. snappy/snap/find_field.py +372 -0
  439. snappy/snap/fox_milnor.py +271 -0
  440. snappy/snap/fundamental_polyhedron.py +569 -0
  441. snappy/snap/generators.py +39 -0
  442. snappy/snap/interval_reps.py +81 -0
  443. snappy/snap/kernel_structures.py +128 -0
  444. snappy/snap/mcomplex_base.py +18 -0
  445. snappy/snap/nsagetools.py +716 -0
  446. snappy/snap/peripheral/__init__.py +1 -0
  447. snappy/snap/peripheral/dual_cellulation.py +219 -0
  448. snappy/snap/peripheral/link.py +127 -0
  449. snappy/snap/peripheral/peripheral.py +159 -0
  450. snappy/snap/peripheral/surface.py +522 -0
  451. snappy/snap/peripheral/test.py +35 -0
  452. snappy/snap/polished_reps.py +335 -0
  453. snappy/snap/shapes.py +152 -0
  454. snappy/snap/slice_obs_HKL/__init__.py +194 -0
  455. snappy/snap/slice_obs_HKL/basics.py +236 -0
  456. snappy/snap/slice_obs_HKL/direct.py +217 -0
  457. snappy/snap/slice_obs_HKL/poly_norm.py +212 -0
  458. snappy/snap/slice_obs_HKL/rep_theory.py +424 -0
  459. snappy/snap/t3mlite/__init__.py +2 -0
  460. snappy/snap/t3mlite/arrow.py +243 -0
  461. snappy/snap/t3mlite/corner.py +22 -0
  462. snappy/snap/t3mlite/edge.py +172 -0
  463. snappy/snap/t3mlite/face.py +37 -0
  464. snappy/snap/t3mlite/files.py +211 -0
  465. snappy/snap/t3mlite/homology.py +53 -0
  466. snappy/snap/t3mlite/linalg.py +419 -0
  467. snappy/snap/t3mlite/mcomplex.py +1499 -0
  468. snappy/snap/t3mlite/perm4.py +320 -0
  469. snappy/snap/t3mlite/setup.py +12 -0
  470. snappy/snap/t3mlite/simplex.py +199 -0
  471. snappy/snap/t3mlite/spun.py +297 -0
  472. snappy/snap/t3mlite/surface.py +519 -0
  473. snappy/snap/t3mlite/test.py +20 -0
  474. snappy/snap/t3mlite/test_vs_regina.py +86 -0
  475. snappy/snap/t3mlite/tetrahedron.py +109 -0
  476. snappy/snap/t3mlite/vertex.py +42 -0
  477. snappy/snap/test.py +139 -0
  478. snappy/snap/utilities.py +288 -0
  479. snappy/test.py +213 -0
  480. snappy/test_cases.py +263 -0
  481. snappy/testing.py +131 -0
  482. snappy/tiling/__init__.py +2 -0
  483. snappy/tiling/dict_based_set.py +79 -0
  484. snappy/tiling/floor.py +49 -0
  485. snappy/tiling/hyperboloid_dict.py +54 -0
  486. snappy/tiling/iter_utils.py +78 -0
  487. snappy/tiling/lifted_tetrahedron.py +22 -0
  488. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  489. snappy/tiling/quotient_dict.py +70 -0
  490. snappy/tiling/real_hash_dict.py +164 -0
  491. snappy/tiling/test.py +23 -0
  492. snappy/tiling/tile.py +224 -0
  493. snappy/tiling/triangle.py +33 -0
  494. snappy/tkterminal.py +920 -0
  495. snappy/twister/__init__.py +20 -0
  496. snappy/twister/main.py +646 -0
  497. snappy/twister/surfaces/S_0_1 +3 -0
  498. snappy/twister/surfaces/S_0_2 +3 -0
  499. snappy/twister/surfaces/S_0_4 +7 -0
  500. snappy/twister/surfaces/S_0_4_Lantern +8 -0
  501. snappy/twister/surfaces/S_1 +3 -0
  502. snappy/twister/surfaces/S_1_1 +4 -0
  503. snappy/twister/surfaces/S_1_2 +5 -0
  504. snappy/twister/surfaces/S_1_2_5 +6 -0
  505. snappy/twister/surfaces/S_2 +6 -0
  506. snappy/twister/surfaces/S_2_1 +8 -0
  507. snappy/twister/surfaces/S_2_heeg +10 -0
  508. snappy/twister/surfaces/S_3 +8 -0
  509. snappy/twister/surfaces/S_3_1 +10 -0
  510. snappy/twister/surfaces/S_4_1 +12 -0
  511. snappy/twister/surfaces/S_5_1 +14 -0
  512. snappy/twister/surfaces/heeg_fig8 +9 -0
  513. snappy/twister/twister_core.cpython-310-aarch64-linux-gnu.so +0 -0
  514. snappy/upper_halfspace/__init__.py +146 -0
  515. snappy/upper_halfspace/ideal_point.py +29 -0
  516. snappy/verify/__init__.py +13 -0
  517. snappy/verify/canonical.py +542 -0
  518. snappy/verify/complex_volume/__init__.py +18 -0
  519. snappy/verify/complex_volume/adjust_torsion.py +86 -0
  520. snappy/verify/complex_volume/closed.py +168 -0
  521. snappy/verify/complex_volume/compute_ptolemys.py +90 -0
  522. snappy/verify/complex_volume/cusped.py +56 -0
  523. snappy/verify/complex_volume/extended_bloch.py +201 -0
  524. snappy/verify/cusp_translations.py +85 -0
  525. snappy/verify/edge_equations.py +80 -0
  526. snappy/verify/exceptions.py +254 -0
  527. snappy/verify/hyperbolicity.py +224 -0
  528. snappy/verify/interval_newton_shapes_engine.py +523 -0
  529. snappy/verify/interval_tree.py +400 -0
  530. snappy/verify/krawczyk_shapes_engine.py +518 -0
  531. snappy/verify/real_algebra.py +286 -0
  532. snappy/verify/shapes.py +25 -0
  533. snappy/verify/square_extensions.py +1005 -0
  534. snappy/verify/test.py +72 -0
  535. snappy/verify/volume.py +128 -0
  536. snappy/version.py +2 -0
  537. snappy-3.3.dist-info/METADATA +58 -0
  538. snappy-3.3.dist-info/RECORD +541 -0
  539. snappy-3.3.dist-info/WHEEL +6 -0
  540. snappy-3.3.dist-info/entry_points.txt +2 -0
  541. snappy-3.3.dist-info/top_level.txt +28 -0
@@ -0,0 +1,1005 @@
1
+ """
2
+ The square_extensions module provides
3
+ two special classes to give exact representations of the values
4
+ involved when computing a cusp cross section.
5
+
6
+ The method find_shapes_as_complex_sqrt_lin_combinations returns a list of
7
+ shapes as ComplexSqrtLinCombination's. This can be used as input to
8
+ CuspCrossSection. The outputs of CuspCrossSection, including the tilts, will
9
+ then be of type SqrtLinCombination.
10
+
11
+ Consider the real number field N generated by the real and imaginary part of
12
+ the shapes. The edge lengths and the factors used to normalize the cusp areas
13
+ will be square roots in N and thus the tilts will be N-linear combinations of
14
+ square roots in N. To avoid computing in a massive tower of square extensions
15
+ of N, we implement SqrtLinCombination here that provides a special
16
+ implementation of the == operator.
17
+ """
18
+
19
+ import operator
20
+ from functools import reduce
21
+ from ..math_basics import prod
22
+ from ..sage_helper import _within_sage, sage_method, SageNotAvailable
23
+
24
+ __all__ = ['find_shapes_as_complex_sqrt_lin_combinations',
25
+ 'SqrtLinCombination',
26
+ 'ComplexSqrtLinCombination']
27
+
28
+ if _within_sage:
29
+ from sage.rings.complex_interval_field import ComplexIntervalField
30
+ from sage.rings.real_mpfi import RealIntervalField
31
+ from sage.rings.integer import Integer
32
+ from sage.rings.rational import Rational
33
+ from sage.rings.number_field.number_field_element import NumberFieldElement
34
+ from sage.functions.other import sqrt
35
+ from ..sage_helper import create_ComplexNumber
36
+
37
+ _Zero = Integer(0)
38
+ _One = Integer(1)
39
+
40
+ from ..snap import find_field
41
+
42
+ from .real_algebra import field_containing_real_and_imaginary_part_of_number_field
43
+
44
+
45
+ def eval_number_field_elt(elt, root):
46
+ # SageMath 7.6 can no longer evaluate a rational polynomial on an
47
+ # arbitrary type that supports the basic arithmetic
48
+ # operations. Rather, one can only evaluate on inputs that have
49
+ # been registered into its coercion model. Thus we have to
50
+ # evaluate things manually.
51
+ if elt.is_zero():
52
+ return _Zero
53
+ poly = elt.lift()
54
+ R = poly.base_ring()
55
+ coeffs = poly.coefficients()
56
+ exps = poly.exponents()
57
+ powers = [R(1)]
58
+ for i in range(max(exps)):
59
+ powers.append(powers[-1]*root)
60
+ return sum(c*powers[e] for (c, e) in zip(coeffs, exps))
61
+
62
+ # One problem in verifying canonical cell decomposition is that we need to do
63
+ # computations in the real field which contains the real and imaginary part
64
+ # of the shape field.
65
+ #
66
+ # Our first try was using Sage's QQbar which was suggested here:
67
+ # http://ask.sagemath.org/question/25822/number-field-containing-realimaginary-part-of-algebraic-number/
68
+ # But turns out way too slow.
69
+ #
70
+ # Next, we tried to use the LLL-algorithm applied to the real and imaginary part
71
+ # of the generator of the shape field (effectively applying LLL twice, once to
72
+ # find the shape field and then the field containing the real and imaginary part
73
+ # of the shape field).
74
+ # This is implemented in
75
+ # _field_containing_real_and_imaginary_part_of_algebraic_number_LLL.
76
+ # This was still very slow and failed on t11669 and 9 manifolds with 9 tetrahedra.
77
+ #
78
+ # The fastest implementation so far is in real_algebra. The implementation there
79
+ # turns the one complex equation p(z) = 0 defining the number field into two
80
+ # real equations for the real and imaginary part of the complex equation and
81
+ # then uses the resultant to find exact solutions.
82
+
83
+
84
+ @sage_method
85
+ def find_shapes_as_complex_sqrt_lin_combinations(M, prec, degree):
86
+ """
87
+ Given a manifold M, use snap (which uses LLL-algorithm) with the given
88
+ decimal precision and maximal degree to find exact values for the shapes'
89
+ real and imaginary part. Return the shapes as list of
90
+ ComplexSqrtLinCombination's. Return None on failure.
91
+
92
+ Example::
93
+
94
+ sage: from snappy import Manifold
95
+ sage: M=Manifold("m412")
96
+ sage: find_shapes_as_complex_sqrt_lin_combinations(M, 200, 10)
97
+ [ComplexSqrtLinCombination((1/2) * sqrt(1), (x - 1/2) * sqrt(1)), ComplexSqrtLinCombination((1/2) * sqrt(1), (x - 1/2) * sqrt(1)), ComplexSqrtLinCombination((1/2) * sqrt(1), (x - 1/2) * sqrt(1)), ComplexSqrtLinCombination((1/2) * sqrt(1), (x - 1/2) * sqrt(1)), ComplexSqrtLinCombination((1/2) * sqrt(1), (x - 1/2) * sqrt(1))]
98
+ """
99
+
100
+ # We need to find the NumberField that contains the real and imaginary
101
+ # parts of all shapes.
102
+
103
+ # First we try to find the field containing the complex shapes:
104
+ complex_data = M.tetrahedra_field_gens().find_field(prec, degree)
105
+ if not complex_data:
106
+ return None
107
+
108
+ # Split Snap's result
109
+ # complex_root is an ApproximateAlgebraicNumber, the root of the
110
+ # NumberField's defining polynomial
111
+ # exact_complex_shapes are elements in a Sage NumberField
112
+ complex_number_field, complex_root, exact_complex_shapes = complex_data
113
+
114
+ # We now have a generator (complex_root) for the NumberField
115
+ # containing the shapes.
116
+ # Next, we need to find the NumberField containing the real and imaginary
117
+ # part of this generator.
118
+
119
+ real_result = field_containing_real_and_imaginary_part_of_number_field(
120
+ complex_number_field)
121
+
122
+ if not real_result:
123
+ return None
124
+
125
+ real_number_field, real_part, imag_part = real_result
126
+
127
+ # Caches the values of
128
+ # nf.gen_embedding()
129
+ # and RealIntervalField(prec)(nf.gen_embedding())
130
+ # for different precision prec where nf is the NumberField real_number_field
131
+ # in which real_part and imag_part live.
132
+ #
133
+ # This is for speed only. See _get_interval_embedding_from_cache for
134
+ # details.
135
+ embed_cache = {}
136
+
137
+ # The generator of the shape field as the desired return type
138
+ exact_complex_root = ComplexSqrtLinCombination(real_part, imag_part,
139
+ embed_cache=embed_cache)
140
+
141
+ # All shapes are given as polynomials in the generator,
142
+ # so translate them to be of the desired return type
143
+ return [ eval_number_field_elt(exact_complex_shape, exact_complex_root)
144
+ for exact_complex_shape in exact_complex_shapes ]
145
+
146
+
147
+ class SqrtLinCombination():
148
+ """
149
+ A class representing a linear combination
150
+
151
+ c_1 * sqrt(r_1) + c_2 * sqrt(r_2) + ... + c_n * sqrt(r_n)
152
+
153
+ where c_i and r_i have to be of type Integer, Rational or elements
154
+ of the same Sage NumberField with a real embedding (Caution: this is
155
+ assumed but not checked!) such that all r_i are positive (Caution: this is
156
+ not checked during construction!).
157
+
158
+ It implements +, -, * where one of the operators is allowed to be an
159
+ integer or rational.
160
+
161
+ / is only implemented when the denominator has only one term c_1 * sqrt(1).
162
+ sqrt is only implemented for c_1 * sqrt(1) and it is not checked that
163
+ c_1 is positive.
164
+
165
+ == is implemented, but the other comparison operators are not: casting to
166
+ a RealIntervalField is implemented instead and the user can compare the
167
+ intervals.
168
+
169
+ The == operator is implemented by first reducing A == B to D == 0 and then
170
+ converting to a different data type (_FactorizedSqrtLinCombination) that can
171
+ represent linear combinations::
172
+
173
+ D = c_1 * sqrt(r_{1,1}) * sqrt(r_{1,2}) * ... * sqrt(r_{1,k_1})
174
+ + c_2 * sqrt(r_{2,1}) * sqrt(r_{2,2}) * ... * sqrt(r_{2,k_2})
175
+ + ...
176
+ + c_n * sqrt(r_{n,1}) * sqrt(r_{n,2}) * ... * sqrt(r_{n,k_n})
177
+
178
+ by just trivially setting
179
+ k_i = 0 when r_i = 1 and
180
+ r_{i,1} = r_i and k_1 = 1 otherwise.
181
+
182
+ For this data type, multiplying two sqrt(r_{i,j}) with equal r_{i,j} will
183
+ cancel the two sqrt's and apply the common r_{i,j} to the c_i of the result
184
+ instead. Thus, the following procedure for determining whether D == 0 will
185
+ eventually terminate:
186
+
187
+ - if the number of terms n is 0, return True
188
+ - if the number of terms n is 1, return c_1 == 0
189
+ - if there is a r_{i,j} common to each summand, factor it out
190
+ - pick one of the r_{i,j}, split the sum into two parts "left",
191
+ respectively, "right" of all the terms containing sqrt(r_{i,j}),
192
+ respectively, not containing sqrt(r_{i,j}).
193
+ - If left^2 - right^2 == 0 is False, return False.
194
+ (sqrt(r_{i,j})^2 simplifies to r_{i,j} and disappears, so the resulting
195
+ expression is easier and this recursion terminates eventually.)
196
+ - If left == 0 (some comment applies), return True
197
+ - Use interval arithmetic of increasing precision until it is high enough
198
+ to determine the signs of left and right.
199
+ Return True if and only if the signs differ, otherwise False.
200
+
201
+ Examples::
202
+
203
+ sage: from sage.rings.number_field.number_field import NumberField
204
+ sage: from sage.rings.integer import Integer
205
+ sage: from sage.rings.rational import Rational
206
+ sage: from sage.rings.real_mpfr import RealLiteral, RealField
207
+ sage: from sage.rings.real_mpfi import RealIntervalField
208
+ sage: from sage.calculus.var import var
209
+ sage: from sage.functions.other import sqrt
210
+ sage: x = var('x')
211
+ sage: poly = x ** 6 + Rational((3,2))*x**4 + Rational((9,16))*x**2 - Rational((23,64))
212
+ sage: nf = NumberField(poly, 'z', embedding = RealField()(0.56227951206))
213
+ sage: z = nf.gen()
214
+
215
+ sage: A = SqrtLinCombination(z)
216
+ sage: B = SqrtLinCombination(Rational((8,9))*z**4 + Rational((10,9))*z**2 + Rational((2,9)))
217
+ sage: C = SqrtLinCombination(3)
218
+ sage: D = SqrtLinCombination(Integer(5))
219
+ sage: E = SqrtLinCombination(Rational((6,7)))
220
+
221
+ sage: A + B
222
+ (8/9*z^4 + 10/9*z^2 + z + 2/9) * sqrt(1)
223
+ sage: B - E
224
+ (8/9*z^4 + 10/9*z^2 - 40/63) * sqrt(1)
225
+ sage: A + sqrt(B) * sqrt(B)
226
+ (8/9*z^4 + 10/9*z^2 + z + 2/9) * sqrt(1)
227
+ sage: A + sqrt(B) * sqrt(B) + C == A + B + C
228
+ True
229
+ sage: A / E
230
+ (7/6*z) * sqrt(1)
231
+ sage: B / A.sqrt()
232
+ (128/207*z^5 + 376/207*z^3 + 302/207*z) * sqrt(z)
233
+ sage: B / (D * A.sqrt())
234
+ (128/1035*z^5 + 376/1035*z^3 + 302/1035*z) * sqrt(z)
235
+ sage: RIF = RealIntervalField(100)
236
+ sage: RIF(B.sqrt() + E.sqrt())
237
+ 1.73967449622339881238507307209?
238
+ sage: A - B == 0
239
+ False
240
+ sage: (A + B).sqrt()
241
+ (1) * sqrt(8/9*z^4 + 10/9*z^2 + z + 2/9)
242
+ sage: 3 * A.sqrt() + (4 * B).sqrt() + C + 8 == (9 * A).sqrt() + 2 * B.sqrt() + (C * C).sqrt() + 11 - 3
243
+ True
244
+
245
+ """
246
+
247
+ def __init__(self, value=None, d={}, embed_cache=None):
248
+ # Initialize from either a value or a dictionary
249
+
250
+ # c_1 * sqrt(r_1) + c_2 * sqrt(r_2) + ... + c_n * sqrt(r_n)
251
+ #
252
+ # is encoded as dictionary
253
+ #
254
+ # { r_1 : c_1, r_2 : c_2, ..., r_n : c_n }
255
+
256
+ if value is not None:
257
+ if d:
258
+ raise TypeError("SqrtLinCombination has both value and "
259
+ "dictionary.")
260
+
261
+ # Write value as
262
+ # value * sqrt(1)
263
+ #
264
+ # Use empty dictionary when value is zero.
265
+
266
+ self._dict = _filter_zero(
267
+ { _One : _convert_to_allowed_type(value) })
268
+ else:
269
+ # Filter out zero elements
270
+ self._dict = _filter_zero(d)
271
+
272
+ # Set embed cache, see _get_interval_embedding_from_cache for details
273
+ self._embed_cache = embed_cache
274
+
275
+ def parent(self):
276
+ return SqrtLinCombination
277
+
278
+ def __add__(self, other):
279
+ # Try to convert other term to SqrtLinCombination if necessary
280
+ if not isinstance(other, SqrtLinCombination):
281
+ return self + SqrtLinCombination(
282
+ other, embed_cache=_get_embed_cache(self, other))
283
+
284
+ # Add
285
+ d = {}
286
+ for k, v in self._dict.items():
287
+ d[k] = d.get(k, 0) + v
288
+ for k, v in other._dict.items():
289
+ d[k] = d.get(k, 0) + v
290
+ return SqrtLinCombination(
291
+ d=d,
292
+ embed_cache=_get_embed_cache(self, other))
293
+
294
+ def __neg__(self):
295
+ # Negate
296
+ return SqrtLinCombination(
297
+ d={ k: -v for k, v in self._dict.items() },
298
+ embed_cache=self._embed_cache)
299
+
300
+ def __sub__(self, other):
301
+ # Subtract
302
+ return self + (-other)
303
+
304
+ def __mul__(self, other):
305
+ # Try to convert other term to SqrtLinCombination if necessary
306
+ if not isinstance(other, SqrtLinCombination):
307
+ return self * SqrtLinCombination(
308
+ other,
309
+ embed_cache=_get_embed_cache(self, other))
310
+
311
+ # Result
312
+ d = {}
313
+
314
+ # Multiply each term with each term
315
+ for k1, v1 in self._dict.items():
316
+ for k2, v2 in other._dict.items():
317
+ # multiply c_i * sqrt(r_i) * c_j * sqrt(r_j)
318
+
319
+ # c_i * c_j
320
+ p = v1 * v2
321
+
322
+ # Multiplying the two roots sqrt(r_i) sqrt(r_j)
323
+ if k1 == k2:
324
+ # Case r_i = r_j
325
+ # The term becomes (r_i * c_i * c_j) * sqrt(1)
326
+ d[_One] = d.get(_One, 0) + k1 * p
327
+ else:
328
+ # Case r_i != r_j
329
+ # The term becomes (c_i * c_j) * sqrt(r_i * r_j)
330
+ m = k1 * k2
331
+ d[m] = d.get(m, 0) + p
332
+ return SqrtLinCombination(
333
+ d=d, embed_cache=_get_embed_cache(self, other))
334
+
335
+ def inverse(self):
336
+ # The inverse element of c_1 * sqrt(r_1)
337
+ # is (1 / (c_1 * r_1)) * sqrt(r_1)
338
+ l = len(self._dict)
339
+ if l != 1:
340
+ # Do not implement other elements.
341
+ if l == 0:
342
+ # In particular, do not invert 0
343
+ raise ZeroDivisionError('SqrtLinCombination division by zero')
344
+ raise TypeError('SqrtLinCombination division not fully '
345
+ 'implemented')
346
+
347
+ # Iteration over the only term
348
+ for k, v in self._dict.items():
349
+ return SqrtLinCombination(
350
+ d={ k : 1 / (v * k) },
351
+ embed_cache=self._embed_cache)
352
+
353
+ def __div__(self, other):
354
+ # Try to convert other term to SqrtLinCombination if necessary
355
+ if not isinstance(other, SqrtLinCombination):
356
+ return self / SqrtLinCombination(
357
+ other, embed_cache=_get_embed_cache(self, other))
358
+ return self * other.inverse()
359
+
360
+ def __truediv__(self, other):
361
+ return self.__div__(other)
362
+
363
+ def __radd__(self, other):
364
+ return self + other
365
+
366
+ def __rsub__(self, other):
367
+ return (-self) + other
368
+
369
+ def __rmul__(self, other):
370
+ return self * other
371
+
372
+ def __rdiv__(self, other):
373
+ return self.inverse() * other
374
+
375
+ def __rtruediv__(self, other):
376
+ return self.__rdiv__(other)
377
+
378
+ def sqrt(self):
379
+ # Implement sqrt of 0 and c_1 * sqrt(1)
380
+ l = len(self._dict)
381
+ if l == 0:
382
+ # sqrt of 0
383
+ return SqrtLinCombination(
384
+ embed_cache=self._embed_cache)
385
+ if l == 1:
386
+ # Iterate through only term
387
+ for k, v in self._dict.items():
388
+ # Make sure expression in sqrt is 1
389
+ if k != 1:
390
+ raise TypeError('SqrtLinCombination sqrt not fully '
391
+ 'implemented')
392
+ return SqrtLinCombination(
393
+ d={ v: _One},
394
+ embed_cache=self._embed_cache)
395
+ raise TypeError('SqrtLinCombination sqrt not fully implemented')
396
+
397
+ def __repr__(self):
398
+ if self._dict:
399
+ return '+'.join(
400
+ ['(%r) * sqrt(%r)' % (v, k) for k, v in self._dict.items()])
401
+ return '0'
402
+
403
+ def __eq__(self, other):
404
+ """
405
+ Implements the == operator as described above.
406
+ """
407
+ diff = self - other
408
+
409
+ # Convert to type holding linear combinations of factorized
410
+ # sqrts.
411
+ f = _FactorizedSqrtLinCombination.from_sqrt_lin_combination(diff)
412
+ return f.is_zero()
413
+
414
+ def __lt__(self, other):
415
+ raise Exception('Not implemented')
416
+
417
+ def __le__(self, other):
418
+ raise Exception('Not implemented')
419
+
420
+ def __gt__(self, other):
421
+ raise Exception('Not implemented')
422
+
423
+ def __ge__(self, other):
424
+ raise Exception('Not implemented')
425
+
426
+ def _real_mpfi_(self, RIF):
427
+ """
428
+ Convert to interval in given RealIntervalField instance.
429
+ """
430
+
431
+ def eval_term(k, v):
432
+ # Evaluate one term c_i * sqrt(r_i)
433
+ # where c_i = k, r_i = v
434
+ s = _to_RIF(k, RIF, self._embed_cache)
435
+ if not s > 0:
436
+ raise _SqrtException()
437
+ return _to_RIF(v, RIF, self._embed_cache) * s.sqrt()
438
+
439
+ # Sum over all terms
440
+ return sum([eval_term(k, v) for k, v in self._dict.items()], RIF(0))
441
+
442
+ def _sign_numerical(self, prec):
443
+ """
444
+ Use interval arithmetics with precision prec to try to determine the
445
+ sign. If we could not certify the sign, return None.
446
+ The result is a pair (sign, interval).
447
+ """
448
+
449
+ # Evaluate as interval
450
+ RIF = RealIntervalField(prec)
451
+ try:
452
+ interval_val = RIF(self)
453
+ except _SqrtException:
454
+ # This exception happens if we try to take the square root of an
455
+ # interval that contains negative numbers.
456
+ # This is not supposed to happen but if we take the square of a small
457
+ # number and the precision is low, it might happen.
458
+ # It just means we need to use higher precision.
459
+ # So just return "None" to indicate failed certification.
460
+ return None, None
461
+
462
+ # Interval certifies positive sign
463
+ if interval_val > 0:
464
+ return +1, interval_val
465
+ # Interval certified negative sign
466
+ if interval_val < 0:
467
+ return -1, interval_val
468
+ # Interval contains zero and we can't say.
469
+ return None, interval_val
470
+
471
+ def sign_with_interval(self):
472
+ """
473
+ Similar to sign, but for the non-zero case, also return the interval
474
+ certifying the sign - useful for debugging.
475
+ """
476
+ # First try to determine the sign using interval arithmetics in twice
477
+ # the double precision. This is for performance: the exact case can
478
+ # be slow so we try numerically first.
479
+ prec = 106
480
+ numerical_sign, interval_val = self._sign_numerical(prec)
481
+ if numerical_sign is not None:
482
+ # We could determine the sign using interval arithmetics
483
+ # Return the result.
484
+ return numerical_sign, interval_val
485
+
486
+ # Now try to determine whether it is zero using exact arithmetics.
487
+ if self == 0:
488
+ # It is zero
489
+ return 0, 0
490
+
491
+ # We know that the value is non-zero. Increase precision until we have
492
+ # determined the sign using interval arithmetics.
493
+ while True:
494
+ prec *= 2
495
+ numerical_sign, interval_val = self._sign_numerical(prec)
496
+ if numerical_sign is not None:
497
+ return numerical_sign, interval_val
498
+
499
+ def sign(self):
500
+ """
501
+ Returns the +1, 0, -1 depending on whether the value is positive,
502
+ zero or negative. For the zero case, exact arithmetic is used to
503
+ certify. Otherwise, interval arithmetic is used.
504
+ """
505
+ return self.sign_with_interval()[0]
506
+
507
+
508
+ class ComplexSqrtLinCombination():
509
+ """
510
+ A pair (real, imag) of SqrtLinCombinations representing the complex number
511
+ real + imag * I. Supports ``real()``, ``imag()``, ``+``, ``-``, ``*``, ``/``,
512
+ ``abs``, ``conjugate()`` and ``==``.
513
+ """
514
+
515
+ def __init__(self, real, imag=0, embed_cache=None):
516
+ if isinstance(real, SqrtLinCombination):
517
+ self._real = real
518
+ else:
519
+ self._real = SqrtLinCombination(
520
+ real,
521
+ embed_cache=embed_cache)
522
+
523
+ if isinstance(imag, SqrtLinCombination):
524
+ self._imag = imag
525
+ else:
526
+ self._imag = SqrtLinCombination(
527
+ imag,
528
+ embed_cache=embed_cache)
529
+
530
+ def __repr__(self):
531
+ return "ComplexSqrtLinCombination(%r, %r)" % (self._real, self._imag)
532
+
533
+ def real(self):
534
+ """
535
+ Real part.
536
+ """
537
+ return self._real
538
+
539
+ def imag(self):
540
+ """
541
+ Imaginary part.
542
+ """
543
+ return self._imag
544
+
545
+ def __abs__(self):
546
+ """
547
+ Absolute value.
548
+ """
549
+
550
+ return sqrt(self._real * self._real + self._imag * self._imag)
551
+
552
+ def __add__(self, other):
553
+ if not isinstance(other, ComplexSqrtLinCombination):
554
+ return self + ComplexSqrtLinCombination(other)
555
+
556
+ return ComplexSqrtLinCombination(self._real + other._real,
557
+ self._imag + other._imag)
558
+
559
+ def __neg__(self):
560
+ return ComplexSqrtLinCombination(-self._real, -self._imag)
561
+
562
+ def __sub__(self, other):
563
+ return self + (-other)
564
+
565
+ def __mul__(self, other):
566
+ if not isinstance(other, ComplexSqrtLinCombination):
567
+ return self * ComplexSqrtLinCombination(other)
568
+
569
+ return ComplexSqrtLinCombination(
570
+ self._real * other._real - self._imag * other._imag,
571
+ self._real * other._imag + self._imag * other._real)
572
+
573
+ def __div__(self, other):
574
+ if not isinstance(other, ComplexSqrtLinCombination):
575
+ return self / ComplexSqrtLinCombination(other)
576
+
577
+ num = 1 / (other._real * other._real + other._imag * other._imag)
578
+
579
+ return ComplexSqrtLinCombination(
580
+ (self._real * other._real + self._imag * other._imag) * num,
581
+ (other._real * self._imag - self._real * other._imag) * num)
582
+
583
+ def __truediv__(self, other):
584
+ return self.__div__(other)
585
+
586
+ def conjugate(self):
587
+ return ComplexSqrtLinCombination(self._real, -self._imag)
588
+
589
+ def __radd__(self, other):
590
+ return self + other
591
+
592
+ def __rsub__(self, other):
593
+ return (-self) + other
594
+
595
+ def __rmul__(self, other):
596
+ return self * other
597
+
598
+ def __rdiv__(self, other):
599
+ return ComplexSqrtLinCombination(other) / self
600
+
601
+ def __rtruediv__(self, other):
602
+ return self.__rdiv__(other)
603
+
604
+ def __eq__(self, other):
605
+ if not isinstance(other, ComplexSqrtLinCombination):
606
+ return self == ComplexSqrtLinCombination(other)
607
+
608
+ return (self._real == other._real) and (self._imag == other._imag)
609
+
610
+ def __ne__(self, other):
611
+ return not (self == other)
612
+
613
+ def __lt__(self, other):
614
+ raise TypeError('No order on complex numbers.')
615
+
616
+ def __le__(self, other):
617
+ raise TypeError('No order on complex numbers.')
618
+
619
+ def __gt__(self, other):
620
+ raise TypeError('No order on complex numbers.')
621
+
622
+ def __ge__(self, other):
623
+ raise TypeError('No order on complex numbers.')
624
+
625
+ def _complex_mpfi_(self, CIF):
626
+ """
627
+ Convert to complex interval in given ComplexIntervalField instance.
628
+ """
629
+
630
+ # Get corresponding RealIntervalField
631
+ RIF = CIF(0).real().parent()
632
+ # And just pair
633
+ return CIF(RIF(self._real), RIF(self._imag))
634
+
635
+
636
+ class _SqrtException(Exception):
637
+ pass
638
+
639
+
640
+ class _FactorizedSqrtLinCombination():
641
+ def __init__(self, d={}, embed_cache=None):
642
+ # c_1 * sqrt(r_{1,1}) * sqrt(r_{1,2}) * ... * sqrt(r_{1,k_1})
643
+ # + c_2 * sqrt(r_{2,1}) * sqrt(r_{2,2}) * ... * sqrt(r_{2,k_2})
644
+ # + ...
645
+ # + c_n * sqrt(r_{n,1}) * sqrt(r_{n,2}) * ... * sqrt(r_{n,k_n})
646
+ #
647
+ # is encoded by a dictionary
648
+ #
649
+ # { frozenset([r_{1,1}, r_{1,2}, ..., r_{1,k_1}]) : c_1,
650
+ # frozenset([r_{2,1}, r_{2,2}, ..., r_{2,k_2}]) : c_2,
651
+ # ...,
652
+ # frozenset([r_{n,1}, r_{n,2}, ..., r_{n,k_n}]) : c_n }
653
+
654
+ self._dict = _filter_zero(d)
655
+
656
+ # Set embed cache, see _get_interval_embedding_from_cache for details
657
+ self._embed_cache = embed_cache
658
+
659
+ def _real_mpfi_(self, RIF):
660
+
661
+ def eval_term(k, v):
662
+ # Evaluate one term
663
+ # c_i * sqrt(r_{i,1}) * sqrt(r_{i,2}) * ... * sqrt(r_{i,k_2})
664
+ # where c_i is stored in v
665
+ # and k is the set of r_{i,j}
666
+
667
+ # Take the product of all r_{i,j} after converting to intervals
668
+ pr = prod([_to_RIF(t, RIF, self._embed_cache) for t in k],
669
+ RIF(1))
670
+
671
+ # Raise exception if interval isn't positive
672
+ if not pr > 0:
673
+ raise _SqrtException()
674
+
675
+ # Return interval for term
676
+ return pr.sqrt() * _to_RIF(v, RIF, self._embed_cache)
677
+
678
+ # Sum over all terms
679
+ return sum([eval_term(k, v) for k, v in self._dict.items()], RIF(0))
680
+
681
+ def __repr__(self):
682
+ if not self._dict:
683
+ return '0'
684
+
685
+ def term(item):
686
+ k, v = item
687
+ b = '(%r)' % v
688
+ for s in k:
689
+ b += ' * sqrt(%r)' % s
690
+ return b
691
+
692
+ return '+'.join([term(item) for item in self._dict.items()])
693
+
694
+ @staticmethod
695
+ def from_sqrt_lin_combination(l):
696
+ """
697
+ Construct from a SqrtLinCombination.
698
+ """
699
+
700
+ # Need to change encoding, see __init__
701
+ def to_set(k):
702
+ if k == _One:
703
+ return frozenset()
704
+ else:
705
+ return frozenset([k])
706
+
707
+ return _FactorizedSqrtLinCombination({
708
+ to_set(k): v for k, v in l._dict.items()},
709
+ embed_cache=l._embed_cache)
710
+
711
+ def __add__(self, other):
712
+ # Add
713
+ d = {}
714
+ for k, v in self._dict.items():
715
+ d[k] = d.get(k, 0) + v
716
+ for k, v in other._dict.items():
717
+ d[k] = d.get(k, 0) + v
718
+ return _FactorizedSqrtLinCombination(
719
+ d,
720
+ embed_cache=_get_embed_cache(self, other))
721
+
722
+ def __neg__(self):
723
+ return _FactorizedSqrtLinCombination(
724
+ {k: -v for k, v in self._dict.items()},
725
+ embed_cache=self._embed_cache)
726
+
727
+ def __sub__(self, other):
728
+ return self + (-other)
729
+
730
+ def __mul__(self, other):
731
+ d = {}
732
+ # Multiply each term with each
733
+ for k1, v1 in self._dict.items():
734
+ for k2, v2 in other._dict.items():
735
+ # Multiply
736
+ # c_i * sqrt(r_{i,1}) * ... * sqrt(r_{i,k_i})
737
+ # with
738
+ # c'_i' * sqrt(r'_{i',1}) * ... * sqrt(r'_{i',k'_i'})
739
+ #
740
+ # If sqrt(r) appears in both terms, it becomes
741
+ # sqrt(r) * sqrt(r) = r and is multiplied into the coefficient
742
+ # (this is done by prod(k1 & k2), _One).
743
+ # A sqrt(r) appearing only appearing in one term survives
744
+ # (k1^k2)
745
+
746
+ k = k1 ^ k2
747
+ v = v1 * v2 * prod(k1 & k2, _One)
748
+ d[k] = d.get(k, 0) + v
749
+ return _FactorizedSqrtLinCombination(
750
+ d, embed_cache=_get_embed_cache(self, other))
751
+
752
+ def is_zero(self):
753
+ """
754
+ Returns True if it is zero, False otherwise.
755
+ """
756
+
757
+ # Implements the algorithm for operator == described in
758
+ # SqrtLinCombination
759
+
760
+ # The case of no terms n = 0
761
+ if not self._dict:
762
+ return True
763
+
764
+ # Case of one term n = 1
765
+ if len(self._dict) == 1:
766
+ return _first(self._dict.values()) == 0
767
+
768
+ # Find all r_{i,j} common to all summands
769
+ common_terms = reduce(
770
+ operator.and_, self._dict.keys())
771
+
772
+ # Factor them out
773
+ d = {k - common_terms: v for k, v in self._dict.items()}
774
+
775
+ # Pick one r_{i,j}
776
+ term = _firstfirst(d.keys())
777
+
778
+ # Split the summands into "left" and "right"
779
+ left = _FactorizedSqrtLinCombination(
780
+ { k: v for k, v in d.items() if term in k },
781
+ embed_cache=self._embed_cache)
782
+ right = _FactorizedSqrtLinCombination(
783
+ { k: v for k, v in d.items() if term not in k},
784
+ embed_cache=self._embed_cache)
785
+
786
+ # Check left^2 - right^2 == 0
787
+ if not (left * left - right * right).is_zero():
788
+ return False
789
+
790
+ # Check left == 0
791
+ if left.is_zero():
792
+ return True
793
+
794
+ # Start with double precision and then increase until we could
795
+ # determine the signs of left and right
796
+ prec = 53
797
+ while True:
798
+ # Determine signs, None indicates the signs couldn't be certified
799
+ opposite_signs = _opposite_signs(left, right, prec)
800
+ if opposite_signs is not None:
801
+ # Done
802
+ return opposite_signs
803
+
804
+ # Otherwise, increase precision
805
+ prec *= 2
806
+
807
+
808
+ def _opposite_signs(left, right, prec):
809
+ """
810
+ Given two objects left and right that can be coerced to real interval of
811
+ the given precision, try to certify their signs. If succeed, return True
812
+ if the signs are opposite and False otherwise. If failed, return None.
813
+ """
814
+
815
+ # Try to cast the elements to real intervals
816
+ RIF = RealIntervalField(prec)
817
+ try:
818
+ left_interval = RIF(left)
819
+ right_interval = RIF(right)
820
+ except _SqrtException:
821
+ # This exception happens if we try to take the square root of an
822
+ # interval that contains negative numbers.
823
+ # This is not supposed to happen but if we take the square of a small
824
+ # number and the precision is low, it might happen.
825
+ # It just means we need to use higher precision.
826
+ # So just return "None" to indicate failed certification.
827
+ return None
828
+
829
+ # Try to determine sign of left expression.
830
+ left_negative = bool(left_interval < 0)
831
+ left_positive = bool(left_interval > 0)
832
+ left_determined = left_negative or left_positive
833
+
834
+ # Try to determine sign of right expression
835
+ right_negative = bool(right_interval < 0)
836
+ right_positive = bool(right_interval > 0)
837
+ right_determined = right_negative or right_positive
838
+
839
+ # If both signs could be determined
840
+ if left_determined and right_determined:
841
+ # Return true if and only if signs are opposite
842
+ return left_positive ^ right_positive
843
+
844
+ # At least one sign couldn't be determined.
845
+ return None
846
+
847
+
848
+ def _first(iterable):
849
+ """
850
+ Return first element of iterable.
851
+ """
852
+ for i in iterable:
853
+ return i
854
+
855
+
856
+ def _firstfirst(iterable):
857
+ """
858
+ Given a nested iterable, i.e., list of lists, return the first element
859
+ of the first non-empty element.
860
+ """
861
+ for i in iterable:
862
+ for j in i:
863
+ return j
864
+
865
+
866
+ def _filter_zero(d):
867
+ """
868
+ Given a dict, filter out all items where the value is 0.
869
+ """
870
+ return {k: v for k, v in d.items() if v != 0}
871
+
872
+
873
+ def _convert_to_allowed_type(number):
874
+ """
875
+ When given a Python int, convert to Sage Integer (so that
876
+ division of two integers gives a Rational). Otherwise,
877
+ check that the type is allowed.
878
+ """
879
+
880
+ if isinstance(number, int):
881
+ return Integer(number)
882
+ if isinstance(number, Integer):
883
+ return number
884
+ if isinstance(number, Rational):
885
+ return number
886
+ if isinstance(number, NumberFieldElement):
887
+ return number
888
+
889
+ raise Exception("Not an allowed type")
890
+
891
+
892
+ def _get_embed_cache(l1, l2):
893
+ """
894
+ Given objects of type SqrtLinCombination or _FactorizedSqrtLinCombination
895
+ return the first _embed_cache that is not None.
896
+ For example, one SqrtLinCombination might be instantiated from an
897
+ Integer and the other from an element in the number field that we are
898
+ currently working in. Then only the latter one has an _embed_cache. Thus,
899
+ the need for this function when adding, multiplying, ... those two
900
+ instances.
901
+ """
902
+ for l in [l1, l2]:
903
+ if ((isinstance(l, SqrtLinCombination) or
904
+ isinstance(l, _FactorizedSqrtLinCombination)) and
905
+ l._embed_cache is not None):
906
+ return l._embed_cache
907
+
908
+ return None
909
+
910
+
911
+ def _get_interval_embedding_from_cache(nf, RIF, cache):
912
+ """
913
+ Evaluate RIF(nf.gen_embedding()) where RIF is a RealIntervalField with
914
+ some precision. This is a real interval that is guaranteed to contain the
915
+ preferred root of the defining polynomial of the number field.
916
+
917
+ To avoid re-evaluation, use cache which is (a reference) to a python
918
+ dictionary.
919
+
920
+ The idea is that while working over one number field, all instances of
921
+ (_Factorized)SqrtLinCombination have a reference to the same (shared) python
922
+ dictionary and fill it in as needed.
923
+
924
+ Unfortunately, the reference to the cache needs to passed down along a lot
925
+ of places. There might be a nicer mechanism for doing this.
926
+ """
927
+
928
+ # Cache is None (vs an empty dictionary) means that we do not wish to use
929
+ # a cache.
930
+
931
+ # Uncomment to debug performance problems that are suspected to come
932
+ # from the reference to the cache not being passed along
933
+ # if cache is None:
934
+ # print("Warning: No cache used")
935
+
936
+ # The key 'gen_embedding' holds the value of nf.gen_embedding()
937
+ if cache is not None and 'gen_embedding' in cache:
938
+ # We can read it from cache
939
+ gen_embedding = cache['gen_embedding']
940
+ else:
941
+ # We need to evaluate it
942
+ gen_embedding = nf.gen_embedding()
943
+ if cache is not None:
944
+ # Save in cache for future use
945
+ cache['gen_embedding'] = gen_embedding
946
+
947
+ # Get the desired precision of the RealIntervalField
948
+ prec = RIF.prec()
949
+ # The precision (which is an int) is the key into the cache
950
+ if cache is not None and prec in cache:
951
+ # RIF(nf.gen_embedding()) is in the cache
952
+ # We can just return the result
953
+ return cache[prec]
954
+
955
+ # We need to actually compute it.
956
+ interval = RIF(gen_embedding)
957
+ if cache is not None:
958
+ # Save in cache for future use.
959
+ cache[prec] = interval
960
+
961
+ return interval
962
+
963
+
964
+ def _to_RIF(x, RIF, embed_cache=None):
965
+ """
966
+ Given a Sage Integer, Rational or an element x in a
967
+ Sage NumberField with a real embedding and an instance
968
+ of a RealIntervalField to specify the desired precision,
969
+ return a real interval containing the true value of x.
970
+
971
+ Warning: one can actually call RIF(x) and get an interval, but I have
972
+ found examples where that interval does not contain the true value!
973
+ Seems a bug in Sage. CIF(x) doesn't work, so maybe there is just some
974
+ sequence of casts going on to convert x to an interval that wasn't
975
+ anticipated.
976
+ """
977
+ # Handle Integer and Rational case
978
+ if isinstance(x, Integer) or isinstance(x, Rational):
979
+ return RIF(x)
980
+
981
+ # Get the number field
982
+ nf = x.parent()
983
+
984
+ # Get the generator of number field as interval
985
+ # The code is equivalent to root = RIF(nf.gen_embedding()) but
986
+ # caches the result.
987
+ root = _get_interval_embedding_from_cache(nf, RIF, embed_cache)
988
+
989
+ # Sanity check on the root. The polynomial should be
990
+ # zero at it, so the interval has to contain zero.
991
+ # This does not certify it. To certify, we would need
992
+ # to take each end point of the interval, evaluate
993
+ # it using interval arithmetics and check for opposite
994
+ # signs
995
+ if not nf.defining_polynomial()(root).contains_zero():
996
+ raise Exception("Root failed test.")
997
+
998
+ # Evaluate the polynomial representing the element in the number field
999
+ # at the root
1000
+ return x.lift()(root)
1001
+
1002
+
1003
+ if __name__ == '__main__':
1004
+ import doctest
1005
+ doctest.testmod()