snappy 3.2__cp313-cp313-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (503) hide show
  1. snappy/CyOpenGL.cpython-313-darwin.so +0 -0
  2. snappy/SnapPy.cpython-313-darwin.so +0 -0
  3. snappy/SnapPy.ico +0 -0
  4. snappy/SnapPy.png +0 -0
  5. snappy/SnapPyHP.cpython-313-darwin.so +0 -0
  6. snappy/__init__.py +760 -0
  7. snappy/app.py +605 -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 +38 -0
  13. snappy/cusps/cusp_area_matrix.py +101 -0
  14. snappy/cusps/cusp_areas_from_matrix.py +173 -0
  15. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  16. snappy/cusps/test.py +21 -0
  17. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  18. snappy/database.py +454 -0
  19. snappy/db_utilities.py +79 -0
  20. snappy/decorated_isosig.py +710 -0
  21. snappy/dev/__init__.py +0 -0
  22. snappy/dev/extended_ptolemy/__init__.py +8 -0
  23. snappy/dev/extended_ptolemy/closed.py +106 -0
  24. snappy/dev/extended_ptolemy/complexVolumesClosed.py +149 -0
  25. snappy/dev/extended_ptolemy/direct.py +42 -0
  26. snappy/dev/extended_ptolemy/extended.py +406 -0
  27. snappy/dev/extended_ptolemy/giac_helper.py +43 -0
  28. snappy/dev/extended_ptolemy/giac_rur.py +129 -0
  29. snappy/dev/extended_ptolemy/gluing.py +46 -0
  30. snappy/dev/extended_ptolemy/phc_wrapper.py +220 -0
  31. snappy/dev/extended_ptolemy/printMatrices.py +70 -0
  32. snappy/dev/vericlosed/__init__.py +1 -0
  33. snappy/dev/vericlosed/computeApproxHyperbolicStructureNew.py +159 -0
  34. snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +90 -0
  35. snappy/dev/vericlosed/computeVerifiedHyperbolicStructure.py +111 -0
  36. snappy/dev/vericlosed/gimbalLoopFinder.py +130 -0
  37. snappy/dev/vericlosed/hyperbolicStructure.py +313 -0
  38. snappy/dev/vericlosed/krawczykCertifiedEdgeLengthsEngine.py +165 -0
  39. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +122 -0
  40. snappy/dev/vericlosed/orb/__init__.py +1 -0
  41. snappy/dev/vericlosed/orb/orb_solution_for_snappea_finite_triangulation_mac +0 -0
  42. snappy/dev/vericlosed/parseVertexGramMatrixFile.py +47 -0
  43. snappy/dev/vericlosed/polishApproxHyperbolicStructure.py +61 -0
  44. snappy/dev/vericlosed/test.py +54 -0
  45. snappy/dev/vericlosed/truncatedComplex.py +176 -0
  46. snappy/dev/vericlosed/verificationError.py +58 -0
  47. snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +177 -0
  48. snappy/doc/_images/SnapPy-196.png +0 -0
  49. snappy/doc/_images/geodesics.jpg +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 +51 -0
  61. snappy/doc/_sources/credits.rst.txt +75 -0
  62. snappy/doc/_sources/development.rst.txt +259 -0
  63. snappy/doc/_sources/index.rst.txt +182 -0
  64. snappy/doc/_sources/installing.rst.txt +247 -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 +355 -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 +925 -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 +156 -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 +199 -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 +620 -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 +427 -0
  152. snappy/doc/credits.html +181 -0
  153. snappy/doc/development.html +384 -0
  154. snappy/doc/genindex.html +1331 -0
  155. snappy/doc/index.html +262 -0
  156. snappy/doc/installing.html +346 -0
  157. snappy/doc/manifold.html +3452 -0
  158. snappy/doc/manifoldhp.html +180 -0
  159. snappy/doc/news.html +388 -0
  160. snappy/doc/objects.inv +0 -0
  161. snappy/doc/other.html +161 -0
  162. snappy/doc/platonic_census.html +375 -0
  163. snappy/doc/plink.html +210 -0
  164. snappy/doc/ptolemy.html +254 -0
  165. snappy/doc/ptolemy_classes.html +1144 -0
  166. snappy/doc/ptolemy_examples1.html +409 -0
  167. snappy/doc/ptolemy_examples2.html +471 -0
  168. snappy/doc/ptolemy_examples3.html +414 -0
  169. snappy/doc/ptolemy_examples4.html +195 -0
  170. snappy/doc/ptolemy_prelim.html +248 -0
  171. snappy/doc/py-modindex.html +165 -0
  172. snappy/doc/screenshots.html +141 -0
  173. snappy/doc/search.html +135 -0
  174. snappy/doc/searchindex.js +1 -0
  175. snappy/doc/snap.html +202 -0
  176. snappy/doc/snappy.html +181 -0
  177. snappy/doc/spherogram.html +1211 -0
  178. snappy/doc/todo.html +166 -0
  179. snappy/doc/triangulation.html +1584 -0
  180. snappy/doc/tutorial.html +159 -0
  181. snappy/doc/verify.html +330 -0
  182. snappy/doc/verify_internals.html +1235 -0
  183. snappy/drilling/__init__.py +456 -0
  184. snappy/drilling/barycentric.py +103 -0
  185. snappy/drilling/constants.py +5 -0
  186. snappy/drilling/crush.py +270 -0
  187. snappy/drilling/cusps.py +125 -0
  188. snappy/drilling/debug.py +242 -0
  189. snappy/drilling/epsilons.py +6 -0
  190. snappy/drilling/exceptions.py +55 -0
  191. snappy/drilling/moves.py +620 -0
  192. snappy/drilling/peripheral_curves.py +210 -0
  193. snappy/drilling/perturb.py +188 -0
  194. snappy/drilling/shorten.py +36 -0
  195. snappy/drilling/subdivide.py +274 -0
  196. snappy/drilling/test.py +23 -0
  197. snappy/drilling/test_cases.py +126 -0
  198. snappy/drilling/tracing.py +351 -0
  199. snappy/exceptions.py +26 -0
  200. snappy/export_stl.py +120 -0
  201. snappy/exterior_to_link/__init__.py +2 -0
  202. snappy/exterior_to_link/barycentric_geometry.py +463 -0
  203. snappy/exterior_to_link/exceptions.py +6 -0
  204. snappy/exterior_to_link/geodesic_map.json +14408 -0
  205. snappy/exterior_to_link/hyp_utils.py +112 -0
  206. snappy/exterior_to_link/link_projection.py +323 -0
  207. snappy/exterior_to_link/main.py +197 -0
  208. snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
  209. snappy/exterior_to_link/mcomplex_with_link.py +687 -0
  210. snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
  211. snappy/exterior_to_link/pl_utils.py +491 -0
  212. snappy/exterior_to_link/put_in_S3.py +156 -0
  213. snappy/exterior_to_link/rational_linear_algebra.py +123 -0
  214. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
  215. snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
  216. snappy/exterior_to_link/stored_moves.py +475 -0
  217. snappy/exterior_to_link/test.py +31 -0
  218. snappy/filedialog.py +28 -0
  219. snappy/geometric_structure/__init__.py +212 -0
  220. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  221. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
  222. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
  223. snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
  224. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
  225. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
  226. snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
  227. snappy/geometric_structure/geodesic/__init__.py +0 -0
  228. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  229. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  230. snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
  231. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  232. snappy/geometric_structure/geodesic/constants.py +6 -0
  233. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  234. snappy/geometric_structure/geodesic/fixed_points.py +93 -0
  235. snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
  236. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  237. snappy/geometric_structure/geodesic/line.py +30 -0
  238. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  239. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
  240. snappy/geometric_structure/test.py +22 -0
  241. snappy/gui.py +121 -0
  242. snappy/horoviewer.py +443 -0
  243. snappy/hyperboloid/__init__.py +212 -0
  244. snappy/hyperboloid/distances.py +245 -0
  245. snappy/hyperboloid/horoball.py +19 -0
  246. snappy/hyperboloid/line.py +35 -0
  247. snappy/hyperboloid/point.py +9 -0
  248. snappy/hyperboloid/triangle.py +29 -0
  249. snappy/info_icon.gif +0 -0
  250. snappy/infowindow.py +65 -0
  251. snappy/isometry_signature.py +382 -0
  252. snappy/len_spec/__init__.py +596 -0
  253. snappy/len_spec/geodesic_info.py +110 -0
  254. snappy/len_spec/geodesic_key_info_dict.py +117 -0
  255. snappy/len_spec/geodesic_piece.py +143 -0
  256. snappy/len_spec/geometric_structure.py +182 -0
  257. snappy/len_spec/geometry.py +80 -0
  258. snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
  259. snappy/len_spec/spine.py +206 -0
  260. snappy/len_spec/test.py +24 -0
  261. snappy/len_spec/test_cases.py +69 -0
  262. snappy/len_spec/tile.py +275 -0
  263. snappy/len_spec/word.py +86 -0
  264. snappy/manifolds/HTWKnots/alternating.gz +0 -0
  265. snappy/manifolds/HTWKnots/nonalternating.gz +0 -0
  266. snappy/manifolds/__init__.py +3 -0
  267. snappy/math_basics.py +176 -0
  268. snappy/matrix.py +525 -0
  269. snappy/number.py +657 -0
  270. snappy/numeric_output_checker.py +345 -0
  271. snappy/pari.py +41 -0
  272. snappy/phone_home.py +57 -0
  273. snappy/polyviewer.py +259 -0
  274. snappy/ptolemy/__init__.py +17 -0
  275. snappy/ptolemy/component.py +103 -0
  276. snappy/ptolemy/coordinates.py +2290 -0
  277. snappy/ptolemy/fieldExtensions.py +153 -0
  278. snappy/ptolemy/findLoops.py +473 -0
  279. snappy/ptolemy/geometricRep.py +59 -0
  280. snappy/ptolemy/homology.py +165 -0
  281. snappy/ptolemy/magma/default.magma_template +229 -0
  282. snappy/ptolemy/magma/radicalsOfPrimaryDecomposition.magma_template +79 -0
  283. snappy/ptolemy/manifoldMethods.py +395 -0
  284. snappy/ptolemy/matrix.py +350 -0
  285. snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +113 -0
  286. snappy/ptolemy/polynomial.py +857 -0
  287. snappy/ptolemy/processComponents.py +173 -0
  288. snappy/ptolemy/processFileBase.py +247 -0
  289. snappy/ptolemy/processFileDispatch.py +46 -0
  290. snappy/ptolemy/processMagmaFile.py +392 -0
  291. snappy/ptolemy/processRurFile.py +150 -0
  292. snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +102 -0
  293. snappy/ptolemy/ptolemyObstructionClass.py +64 -0
  294. snappy/ptolemy/ptolemyVariety.py +1029 -0
  295. snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +140 -0
  296. snappy/ptolemy/reginaWrapper.py +698 -0
  297. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  298. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  299. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  300. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  301. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  302. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  303. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  304. snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  305. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  306. snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  307. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c0.magma_out.bz2 +0 -0
  308. snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  309. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  310. snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c1.magma_out.bz2 +0 -0
  311. snappy/ptolemy/rur.py +545 -0
  312. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +277 -0
  313. snappy/ptolemy/test.py +1126 -0
  314. snappy/ptolemy/testing_files/3_1__sl2_c0.magma_out.bz2 +0 -0
  315. snappy/ptolemy/testing_files/3_1__sl2_c1.magma_out.bz2 +0 -0
  316. snappy/ptolemy/testing_files/4_1__sl2_c0.magma_out.bz2 +0 -0
  317. snappy/ptolemy/testing_files/4_1__sl2_c1.magma_out.bz2 +0 -0
  318. snappy/ptolemy/testing_files/4_1__sl3_c0.magma_out.bz2 +0 -0
  319. snappy/ptolemy/testing_files/4_1__sl4_c0.magma_out.bz2 +0 -0
  320. snappy/ptolemy/testing_files/4_1__sl4_c1.magma_out.bz2 +0 -0
  321. snappy/ptolemy/testing_files/5_2__sl2_c0.magma_out.bz2 +0 -0
  322. snappy/ptolemy/testing_files/5_2__sl2_c1.magma_out.bz2 +0 -0
  323. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
  324. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
  325. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
  326. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
  327. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
  328. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
  329. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
  330. snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
  331. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c0.magma_out +95 -0
  332. snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c1.magma_out +95 -0
  333. snappy/ptolemy/testing_files/m015__sl3_c0.magma_out.bz2 +0 -0
  334. snappy/ptolemy/testing_files/m135__sl2_c0.magma_out.bz2 +0 -0
  335. snappy/ptolemy/testing_files/m135__sl2_c1.magma_out.bz2 +0 -0
  336. snappy/ptolemy/testing_files/m135__sl2_c2.magma_out.bz2 +0 -0
  337. snappy/ptolemy/testing_files/m135__sl2_c3.magma_out.bz2 +0 -0
  338. snappy/ptolemy/testing_files/m135__sl2_c4.magma_out.bz2 +0 -0
  339. snappy/ptolemy/testing_files/m135__sl2_c5.magma_out.bz2 +0 -0
  340. snappy/ptolemy/testing_files/m135__sl2_c6.magma_out.bz2 +0 -0
  341. snappy/ptolemy/testing_files/m135__sl2_c7.magma_out.bz2 +0 -0
  342. snappy/ptolemy/testing_files/s000__sl2_c0.magma_out.bz2 +0 -0
  343. snappy/ptolemy/testing_files/s000__sl2_c1.magma_out.bz2 +0 -0
  344. snappy/ptolemy/testing_files/t00000__sl2_c0.magma_out.bz2 +0 -0
  345. snappy/ptolemy/testing_files/t00000__sl2_c1.magma_out.bz2 +0 -0
  346. snappy/ptolemy/testing_files/v0000__sl2_c0.magma_out.bz2 +0 -0
  347. snappy/ptolemy/testing_files/v0000__sl2_c1.magma_out.bz2 +0 -0
  348. snappy/ptolemy/testing_files/v0000__sl2_c2.magma_out.bz2 +0 -0
  349. snappy/ptolemy/testing_files/v0000__sl2_c3.magma_out.bz2 +0 -0
  350. snappy/ptolemy/testing_files_generalized/m003__sl2_c0.magma_out.bz2 +0 -0
  351. snappy/ptolemy/testing_files_generalized/m003__sl2_c1.magma_out.bz2 +0 -0
  352. snappy/ptolemy/testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
  353. snappy/ptolemy/testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
  354. snappy/ptolemy/testing_files_generalized/m004__sl2_c0.magma_out.bz2 +0 -0
  355. snappy/ptolemy/testing_files_generalized/m004__sl2_c1.magma_out.bz2 +0 -0
  356. snappy/ptolemy/testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
  357. snappy/ptolemy/testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
  358. snappy/ptolemy/testing_files_rur/m052__sl3_c0.rur.bz2 +0 -0
  359. snappy/ptolemy/utilities.py +236 -0
  360. snappy/raytracing/__init__.py +64 -0
  361. snappy/raytracing/additional_horospheres.py +64 -0
  362. snappy/raytracing/additional_len_spec_choices.py +63 -0
  363. snappy/raytracing/cohomology_fractal.py +197 -0
  364. snappy/raytracing/eyeball.py +123 -0
  365. snappy/raytracing/finite_raytracing_data.py +237 -0
  366. snappy/raytracing/finite_viewer.py +590 -0
  367. snappy/raytracing/geodesic_tube_info.py +174 -0
  368. snappy/raytracing/geodesics.py +246 -0
  369. snappy/raytracing/geodesics_window.py +258 -0
  370. snappy/raytracing/gui_utilities.py +293 -0
  371. snappy/raytracing/hyperboloid_navigation.py +556 -0
  372. snappy/raytracing/hyperboloid_utilities.py +234 -0
  373. snappy/raytracing/ideal_raytracing_data.py +592 -0
  374. snappy/raytracing/inside_viewer.py +974 -0
  375. snappy/raytracing/pack.py +22 -0
  376. snappy/raytracing/raytracing_data.py +126 -0
  377. snappy/raytracing/raytracing_view.py +454 -0
  378. snappy/raytracing/shaders/Eye.png +0 -0
  379. snappy/raytracing/shaders/NonGeometric.png +0 -0
  380. snappy/raytracing/shaders/__init__.py +101 -0
  381. snappy/raytracing/shaders/fragment.glsl +1744 -0
  382. snappy/raytracing/test.py +29 -0
  383. snappy/raytracing/tooltip.py +146 -0
  384. snappy/raytracing/upper_halfspace_utilities.py +98 -0
  385. snappy/raytracing/view_scale_controller.py +98 -0
  386. snappy/raytracing/zoom_slider/__init__.py +263 -0
  387. snappy/raytracing/zoom_slider/inward.png +0 -0
  388. snappy/raytracing/zoom_slider/inward18.png +0 -0
  389. snappy/raytracing/zoom_slider/outward.png +0 -0
  390. snappy/raytracing/zoom_slider/outward18.png +0 -0
  391. snappy/raytracing/zoom_slider/test.py +20 -0
  392. snappy/sage_helper.py +117 -0
  393. snappy/settings.py +409 -0
  394. snappy/shell.py +53 -0
  395. snappy/snap/__init__.py +114 -0
  396. snappy/snap/character_varieties.py +375 -0
  397. snappy/snap/find_field.py +372 -0
  398. snappy/snap/fundamental_polyhedron.py +569 -0
  399. snappy/snap/generators.py +39 -0
  400. snappy/snap/interval_reps.py +81 -0
  401. snappy/snap/kernel_structures.py +128 -0
  402. snappy/snap/mcomplex_base.py +18 -0
  403. snappy/snap/nsagetools.py +702 -0
  404. snappy/snap/peripheral/__init__.py +1 -0
  405. snappy/snap/peripheral/dual_cellulation.py +219 -0
  406. snappy/snap/peripheral/link.py +127 -0
  407. snappy/snap/peripheral/peripheral.py +159 -0
  408. snappy/snap/peripheral/surface.py +522 -0
  409. snappy/snap/peripheral/test.py +35 -0
  410. snappy/snap/polished_reps.py +335 -0
  411. snappy/snap/shapes.py +152 -0
  412. snappy/snap/slice_obs_HKL.py +668 -0
  413. snappy/snap/t3mlite/__init__.py +2 -0
  414. snappy/snap/t3mlite/arrow.py +243 -0
  415. snappy/snap/t3mlite/corner.py +22 -0
  416. snappy/snap/t3mlite/edge.py +172 -0
  417. snappy/snap/t3mlite/face.py +37 -0
  418. snappy/snap/t3mlite/files.py +211 -0
  419. snappy/snap/t3mlite/homology.py +53 -0
  420. snappy/snap/t3mlite/linalg.py +419 -0
  421. snappy/snap/t3mlite/mcomplex.py +1499 -0
  422. snappy/snap/t3mlite/perm4.py +320 -0
  423. snappy/snap/t3mlite/setup.py +12 -0
  424. snappy/snap/t3mlite/simplex.py +199 -0
  425. snappy/snap/t3mlite/spun.py +297 -0
  426. snappy/snap/t3mlite/surface.py +519 -0
  427. snappy/snap/t3mlite/test.py +20 -0
  428. snappy/snap/t3mlite/test_vs_regina.py +86 -0
  429. snappy/snap/t3mlite/tetrahedron.py +109 -0
  430. snappy/snap/t3mlite/vertex.py +42 -0
  431. snappy/snap/test.py +134 -0
  432. snappy/snap/utilities.py +288 -0
  433. snappy/test.py +209 -0
  434. snappy/test_cases.py +263 -0
  435. snappy/testing.py +131 -0
  436. snappy/tiling/__init__.py +2 -0
  437. snappy/tiling/canonical_key_dict.py +59 -0
  438. snappy/tiling/dict_based_set.py +79 -0
  439. snappy/tiling/floor.py +49 -0
  440. snappy/tiling/hyperboloid_dict.py +54 -0
  441. snappy/tiling/iter_utils.py +78 -0
  442. snappy/tiling/lifted_tetrahedron.py +22 -0
  443. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  444. snappy/tiling/real_hash_dict.py +164 -0
  445. snappy/tiling/test.py +23 -0
  446. snappy/tiling/tile.py +215 -0
  447. snappy/tiling/triangle.py +33 -0
  448. snappy/tkterminal.py +920 -0
  449. snappy/twister/__init__.py +20 -0
  450. snappy/twister/main.py +646 -0
  451. snappy/twister/surfaces/S_0_1 +3 -0
  452. snappy/twister/surfaces/S_0_2 +3 -0
  453. snappy/twister/surfaces/S_0_4 +7 -0
  454. snappy/twister/surfaces/S_0_4_Lantern +8 -0
  455. snappy/twister/surfaces/S_1 +3 -0
  456. snappy/twister/surfaces/S_1_1 +4 -0
  457. snappy/twister/surfaces/S_1_2 +5 -0
  458. snappy/twister/surfaces/S_1_2_5 +6 -0
  459. snappy/twister/surfaces/S_2 +6 -0
  460. snappy/twister/surfaces/S_2_1 +8 -0
  461. snappy/twister/surfaces/S_2_heeg +10 -0
  462. snappy/twister/surfaces/S_3 +8 -0
  463. snappy/twister/surfaces/S_3_1 +10 -0
  464. snappy/twister/surfaces/S_4_1 +12 -0
  465. snappy/twister/surfaces/S_5_1 +14 -0
  466. snappy/twister/surfaces/heeg_fig8 +9 -0
  467. snappy/twister/twister_core.cpython-313-darwin.so +0 -0
  468. snappy/upper_halfspace/__init__.py +146 -0
  469. snappy/upper_halfspace/ideal_point.py +26 -0
  470. snappy/verify/__init__.py +13 -0
  471. snappy/verify/canonical.py +542 -0
  472. snappy/verify/complex_volume/__init__.py +18 -0
  473. snappy/verify/complex_volume/adjust_torsion.py +86 -0
  474. snappy/verify/complex_volume/closed.py +168 -0
  475. snappy/verify/complex_volume/compute_ptolemys.py +90 -0
  476. snappy/verify/complex_volume/cusped.py +56 -0
  477. snappy/verify/complex_volume/extended_bloch.py +201 -0
  478. snappy/verify/cusp_translations.py +85 -0
  479. snappy/verify/edge_equations.py +80 -0
  480. snappy/verify/exceptions.py +254 -0
  481. snappy/verify/hyperbolicity.py +224 -0
  482. snappy/verify/interval_newton_shapes_engine.py +523 -0
  483. snappy/verify/interval_tree.py +400 -0
  484. snappy/verify/krawczyk_shapes_engine.py +518 -0
  485. snappy/verify/maximal_cusp_area_matrix/__init__.py +46 -0
  486. snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +419 -0
  487. snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +153 -0
  488. snappy/verify/real_algebra.py +286 -0
  489. snappy/verify/shapes.py +25 -0
  490. snappy/verify/short_slopes.py +200 -0
  491. snappy/verify/square_extensions.py +1005 -0
  492. snappy/verify/test.py +78 -0
  493. snappy/verify/upper_halfspace/__init__.py +9 -0
  494. snappy/verify/upper_halfspace/extended_matrix.py +100 -0
  495. snappy/verify/upper_halfspace/finite_point.py +283 -0
  496. snappy/verify/upper_halfspace/ideal_point.py +426 -0
  497. snappy/verify/volume.py +128 -0
  498. snappy/version.py +2 -0
  499. snappy-3.2.dist-info/METADATA +58 -0
  500. snappy-3.2.dist-info/RECORD +503 -0
  501. snappy-3.2.dist-info/WHEEL +5 -0
  502. snappy-3.2.dist-info/entry_points.txt +2 -0
  503. snappy-3.2.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()