snappy 3.1.1__cp38-cp38-win_amd64.whl → 3.2__cp38-cp38-win_amd64.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 (476) hide show
  1. snappy/CyOpenGL.cp38-win_amd64.pyd +0 -0
  2. snappy/SnapPy.cp38-win_amd64.pyd +0 -0
  3. snappy/SnapPyHP.cp38-win_amd64.pyd +0 -0
  4. snappy/__init__.py +299 -402
  5. snappy/app.py +70 -20
  6. snappy/browser.py +18 -17
  7. snappy/canonical.py +249 -0
  8. snappy/{verify/cusp_shapes.py → cusps/__init__.py} +8 -18
  9. snappy/cusps/cusp_area_matrix.py +101 -0
  10. snappy/{verify/cusp_areas.py → cusps/cusp_areas_from_matrix.py} +23 -39
  11. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  12. snappy/cusps/test.py +21 -0
  13. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  14. snappy/database.py +10 -9
  15. snappy/decorated_isosig.py +337 -114
  16. snappy/dev/extended_ptolemy/complexVolumesClosed.py +40 -7
  17. snappy/dev/extended_ptolemy/extended.py +3 -3
  18. snappy/dev/extended_ptolemy/phc_wrapper.py +10 -10
  19. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +1 -1
  20. snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
  21. snappy/doc/_images/m125_paper_plane.jpg +0 -0
  22. snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
  23. snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
  24. snappy/doc/_sources/additional_classes.rst.txt +40 -40
  25. snappy/doc/_sources/bugs.rst.txt +14 -14
  26. snappy/doc/_sources/censuses.rst.txt +51 -51
  27. snappy/doc/_sources/credits.rst.txt +75 -75
  28. snappy/doc/_sources/development.rst.txt +259 -239
  29. snappy/doc/_sources/index.rst.txt +182 -115
  30. snappy/doc/_sources/installing.rst.txt +247 -264
  31. snappy/doc/_sources/manifold.rst.txt +6 -6
  32. snappy/doc/_sources/manifoldhp.rst.txt +46 -46
  33. snappy/doc/_sources/news.rst.txt +355 -283
  34. snappy/doc/_sources/other.rst.txt +25 -25
  35. snappy/doc/_sources/platonic_census.rst.txt +20 -20
  36. snappy/doc/_sources/plink.rst.txt +102 -102
  37. snappy/doc/_sources/ptolemy.rst.txt +66 -66
  38. snappy/doc/_sources/ptolemy_classes.rst.txt +42 -42
  39. snappy/doc/_sources/ptolemy_examples1.rst.txt +298 -297
  40. snappy/doc/_sources/ptolemy_examples2.rst.txt +363 -363
  41. snappy/doc/_sources/ptolemy_examples3.rst.txt +301 -301
  42. snappy/doc/_sources/ptolemy_examples4.rst.txt +61 -61
  43. snappy/doc/_sources/ptolemy_prelim.rst.txt +105 -105
  44. snappy/doc/_sources/screenshots.rst.txt +21 -21
  45. snappy/doc/_sources/snap.rst.txt +87 -87
  46. snappy/doc/_sources/snappy.rst.txt +28 -28
  47. snappy/doc/_sources/spherogram.rst.txt +103 -103
  48. snappy/doc/_sources/todo.rst.txt +47 -47
  49. snappy/doc/_sources/triangulation.rst.txt +11 -11
  50. snappy/doc/_sources/tutorial.rst.txt +49 -49
  51. snappy/doc/_sources/verify.rst.txt +210 -150
  52. snappy/doc/_sources/verify_internals.rst.txt +79 -90
  53. snappy/doc/_static/basic.css +924 -902
  54. snappy/doc/_static/css/badge_only.css +1 -1
  55. snappy/doc/_static/css/theme.css +1 -1
  56. snappy/doc/_static/doctools.js +1 -1
  57. snappy/doc/_static/documentation_options.js +12 -13
  58. snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
  59. snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
  60. snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
  61. snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
  62. snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  63. snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  64. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  65. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  66. snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
  67. snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
  68. snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
  69. snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
  70. snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
  71. snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
  72. snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
  73. snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
  74. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  75. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  76. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  77. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  78. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  79. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  80. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  81. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  82. snappy/doc/_static/js/versions.js +228 -0
  83. snappy/doc/_static/language_data.js +199 -199
  84. snappy/doc/_static/pygments.css +74 -73
  85. snappy/doc/_static/searchtools.js +125 -71
  86. snappy/doc/_static/snappy_furo.css +33 -33
  87. snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -42
  88. snappy/doc/_static/sphinx_highlight.js +13 -3
  89. snappy/doc/additional_classes.html +1499 -1330
  90. snappy/doc/bugs.html +131 -134
  91. snappy/doc/censuses.html +426 -445
  92. snappy/doc/credits.html +180 -183
  93. snappy/doc/development.html +383 -363
  94. snappy/doc/genindex.html +1330 -1409
  95. snappy/doc/index.html +261 -206
  96. snappy/doc/installing.html +345 -363
  97. snappy/doc/manifold.html +3451 -2839
  98. snappy/doc/manifoldhp.html +179 -182
  99. snappy/doc/news.html +387 -329
  100. snappy/doc/objects.inv +0 -0
  101. snappy/doc/other.html +160 -162
  102. snappy/doc/platonic_census.html +374 -377
  103. snappy/doc/plink.html +209 -212
  104. snappy/doc/ptolemy.html +253 -255
  105. snappy/doc/ptolemy_classes.html +1143 -1146
  106. snappy/doc/ptolemy_examples1.html +408 -410
  107. snappy/doc/ptolemy_examples2.html +470 -473
  108. snappy/doc/ptolemy_examples3.html +413 -416
  109. snappy/doc/ptolemy_examples4.html +194 -197
  110. snappy/doc/ptolemy_prelim.html +247 -250
  111. snappy/doc/py-modindex.html +164 -167
  112. snappy/doc/screenshots.html +140 -142
  113. snappy/doc/search.html +134 -137
  114. snappy/doc/searchindex.js +1 -1
  115. snappy/doc/snap.html +201 -204
  116. snappy/doc/snappy.html +180 -182
  117. snappy/doc/spherogram.html +1210 -1213
  118. snappy/doc/todo.html +165 -168
  119. snappy/doc/triangulation.html +1583 -1474
  120. snappy/doc/tutorial.html +158 -161
  121. snappy/doc/verify.html +329 -275
  122. snappy/doc/verify_internals.html +1234 -1691
  123. snappy/drilling/__init__.py +153 -235
  124. snappy/drilling/barycentric.py +103 -0
  125. snappy/drilling/constants.py +0 -2
  126. snappy/drilling/crush.py +56 -130
  127. snappy/drilling/cusps.py +12 -6
  128. snappy/drilling/debug.py +2 -1
  129. snappy/drilling/exceptions.py +7 -40
  130. snappy/drilling/moves.py +302 -243
  131. snappy/drilling/perturb.py +63 -37
  132. snappy/drilling/shorten.py +36 -0
  133. snappy/drilling/subdivide.py +0 -5
  134. snappy/drilling/test.py +23 -0
  135. snappy/drilling/test_cases.py +126 -0
  136. snappy/drilling/tracing.py +9 -37
  137. snappy/exceptions.py +18 -5
  138. snappy/exterior_to_link/barycentric_geometry.py +2 -4
  139. snappy/exterior_to_link/main.py +8 -7
  140. snappy/exterior_to_link/mcomplex_with_link.py +2 -2
  141. snappy/exterior_to_link/rational_linear_algebra.py +1 -1
  142. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +1 -1
  143. snappy/exterior_to_link/test.py +21 -33
  144. snappy/geometric_structure/__init__.py +212 -0
  145. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  146. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
  147. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
  148. snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
  149. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
  150. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
  151. snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
  152. snappy/geometric_structure/geodesic/__init__.py +0 -0
  153. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  154. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  155. snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
  156. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  157. snappy/geometric_structure/geodesic/constants.py +6 -0
  158. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  159. snappy/{drilling → geometric_structure/geodesic}/fixed_points.py +34 -9
  160. snappy/{drilling/geodesic_info.py → geometric_structure/geodesic/geodesic_start_point_info.py} +139 -180
  161. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  162. snappy/geometric_structure/geodesic/line.py +30 -0
  163. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  164. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
  165. snappy/geometric_structure/test.py +22 -0
  166. snappy/gui.py +23 -13
  167. snappy/horoviewer.py +7 -7
  168. snappy/hyperboloid/__init__.py +96 -31
  169. snappy/hyperboloid/distances.py +245 -0
  170. snappy/hyperboloid/horoball.py +19 -0
  171. snappy/hyperboloid/line.py +35 -0
  172. snappy/hyperboloid/point.py +9 -0
  173. snappy/hyperboloid/triangle.py +29 -0
  174. snappy/isometry_signature.py +382 -0
  175. snappy/len_spec/__init__.py +596 -0
  176. snappy/len_spec/geodesic_info.py +110 -0
  177. snappy/len_spec/geodesic_key_info_dict.py +117 -0
  178. snappy/len_spec/geodesic_piece.py +143 -0
  179. snappy/len_spec/geometric_structure.py +182 -0
  180. snappy/len_spec/geometry.py +80 -0
  181. snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
  182. snappy/len_spec/spine.py +206 -0
  183. snappy/len_spec/test.py +24 -0
  184. snappy/len_spec/test_cases.py +69 -0
  185. snappy/len_spec/tile.py +275 -0
  186. snappy/len_spec/word.py +86 -0
  187. snappy/math_basics.py +39 -13
  188. snappy/matrix.py +52 -9
  189. snappy/number.py +12 -6
  190. snappy/numeric_output_checker.py +2 -3
  191. snappy/pari.py +8 -4
  192. snappy/phone_home.py +2 -1
  193. snappy/polyviewer.py +8 -8
  194. snappy/ptolemy/__init__.py +1 -1
  195. snappy/ptolemy/component.py +2 -2
  196. snappy/ptolemy/coordinates.py +25 -25
  197. snappy/ptolemy/findLoops.py +9 -9
  198. snappy/ptolemy/manifoldMethods.py +27 -29
  199. snappy/ptolemy/polynomial.py +50 -57
  200. snappy/ptolemy/processFileBase.py +60 -0
  201. snappy/ptolemy/ptolemyVariety.py +109 -41
  202. snappy/ptolemy/reginaWrapper.py +4 -4
  203. snappy/ptolemy/rur.py +1 -1
  204. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +9 -9
  205. snappy/ptolemy/test.py +99 -54
  206. snappy/ptolemy/utilities.py +1 -1
  207. snappy/raytracing/__init__.py +64 -0
  208. snappy/raytracing/additional_horospheres.py +64 -0
  209. snappy/raytracing/additional_len_spec_choices.py +63 -0
  210. snappy/raytracing/cohomology_fractal.py +0 -3
  211. snappy/raytracing/eyeball.py +123 -0
  212. snappy/raytracing/finite_raytracing_data.py +17 -17
  213. snappy/raytracing/finite_viewer.py +15 -15
  214. snappy/raytracing/geodesic_tube_info.py +93 -63
  215. snappy/raytracing/geodesics.py +94 -64
  216. snappy/raytracing/geodesics_window.py +56 -34
  217. snappy/raytracing/gui_utilities.py +21 -6
  218. snappy/raytracing/hyperboloid_navigation.py +29 -4
  219. snappy/raytracing/hyperboloid_utilities.py +73 -73
  220. snappy/raytracing/ideal_raytracing_data.py +121 -91
  221. snappy/raytracing/inside_viewer.py +199 -66
  222. snappy/raytracing/pack.py +22 -0
  223. snappy/raytracing/raytracing_data.py +37 -25
  224. snappy/raytracing/raytracing_view.py +70 -65
  225. snappy/raytracing/shaders/Eye.png +0 -0
  226. snappy/raytracing/shaders/NonGeometric.png +0 -0
  227. snappy/raytracing/shaders/__init__.py +39 -3
  228. snappy/raytracing/shaders/fragment.glsl +451 -133
  229. snappy/raytracing/test.py +29 -0
  230. snappy/raytracing/tooltip.py +146 -0
  231. snappy/raytracing/upper_halfspace_utilities.py +42 -9
  232. snappy/sage_helper.py +67 -134
  233. snappy/settings.py +90 -77
  234. snappy/shell.py +2 -0
  235. snappy/snap/character_varieties.py +2 -2
  236. snappy/snap/find_field.py +4 -3
  237. snappy/snap/fundamental_polyhedron.py +2 -2
  238. snappy/snap/kernel_structures.py +5 -1
  239. snappy/snap/nsagetools.py +9 -8
  240. snappy/snap/peripheral/dual_cellulation.py +4 -3
  241. snappy/snap/peripheral/peripheral.py +2 -2
  242. snappy/snap/peripheral/surface.py +5 -5
  243. snappy/snap/peripheral/test.py +1 -1
  244. snappy/snap/polished_reps.py +8 -8
  245. snappy/snap/slice_obs_HKL.py +16 -14
  246. snappy/snap/t3mlite/arrow.py +3 -3
  247. snappy/snap/t3mlite/edge.py +3 -3
  248. snappy/snap/t3mlite/homology.py +2 -2
  249. snappy/snap/t3mlite/mcomplex.py +3 -3
  250. snappy/snap/t3mlite/simplex.py +12 -0
  251. snappy/snap/t3mlite/spun.py +18 -17
  252. snappy/snap/t3mlite/test_vs_regina.py +4 -4
  253. snappy/snap/test.py +37 -53
  254. snappy/snap/utilities.py +4 -5
  255. snappy/test.py +121 -138
  256. snappy/test_cases.py +263 -0
  257. snappy/testing.py +131 -0
  258. snappy/tiling/__init__.py +2 -0
  259. snappy/tiling/canonical_key_dict.py +59 -0
  260. snappy/tiling/dict_based_set.py +79 -0
  261. snappy/tiling/floor.py +49 -0
  262. snappy/tiling/hyperboloid_dict.py +54 -0
  263. snappy/tiling/iter_utils.py +78 -0
  264. snappy/tiling/lifted_tetrahedron.py +22 -0
  265. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  266. snappy/tiling/real_hash_dict.py +164 -0
  267. snappy/tiling/test.py +23 -0
  268. snappy/tiling/tile.py +215 -0
  269. snappy/tiling/triangle.py +33 -0
  270. snappy/tkterminal.py +113 -84
  271. snappy/twister/main.py +1 -7
  272. snappy/twister/twister_core.cp38-win_amd64.pyd +0 -0
  273. snappy/upper_halfspace/__init__.py +78 -17
  274. snappy/verify/__init__.py +3 -7
  275. snappy/verify/{verifyCanonical.py → canonical.py} +78 -70
  276. snappy/verify/complex_volume/adjust_torsion.py +1 -2
  277. snappy/verify/complex_volume/closed.py +13 -13
  278. snappy/verify/complex_volume/cusped.py +6 -6
  279. snappy/verify/complex_volume/extended_bloch.py +5 -8
  280. snappy/verify/{cuspTranslations.py → cusp_translations.py} +1 -1
  281. snappy/verify/edge_equations.py +80 -0
  282. snappy/verify/exceptions.py +0 -55
  283. snappy/verify/{verifyHyperbolicity.py → hyperbolicity.py} +3 -3
  284. snappy/verify/interval_newton_shapes_engine.py +7 -5
  285. snappy/verify/interval_tree.py +5 -5
  286. snappy/verify/krawczyk_shapes_engine.py +17 -18
  287. snappy/verify/maximal_cusp_area_matrix/__init__.py +7 -74
  288. snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +3 -4
  289. snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +1 -1
  290. snappy/verify/{realAlgebra.py → real_algebra.py} +1 -1
  291. snappy/verify/shapes.py +5 -3
  292. snappy/verify/short_slopes.py +39 -41
  293. snappy/verify/{squareExtensions.py → square_extensions.py} +14 -11
  294. snappy/verify/test.py +57 -60
  295. snappy/verify/upper_halfspace/extended_matrix.py +1 -1
  296. snappy/verify/upper_halfspace/finite_point.py +3 -4
  297. snappy/verify/upper_halfspace/ideal_point.py +9 -9
  298. snappy/verify/volume.py +2 -2
  299. snappy/version.py +2 -2
  300. {snappy-3.1.1.dist-info → snappy-3.2.dist-info}/METADATA +14 -10
  301. snappy-3.2.dist-info/RECORD +503 -0
  302. {snappy-3.1.1.dist-info → snappy-3.2.dist-info}/WHEEL +1 -1
  303. {snappy-3.1.1.dist-info → snappy-3.2.dist-info}/top_level.txt +6 -1
  304. snappy/__pycache__/__init__.cpython-38.pyc +0 -0
  305. snappy/__pycache__/browser.cpython-38.pyc +0 -0
  306. snappy/__pycache__/cache.cpython-38.pyc +0 -0
  307. snappy/__pycache__/database.cpython-38.pyc +0 -0
  308. snappy/__pycache__/db_utilities.cpython-38.pyc +0 -0
  309. snappy/__pycache__/decorated_isosig.cpython-38.pyc +0 -0
  310. snappy/__pycache__/exceptions.cpython-38.pyc +0 -0
  311. snappy/__pycache__/export_stl.cpython-38.pyc +0 -0
  312. snappy/__pycache__/filedialog.cpython-38.pyc +0 -0
  313. snappy/__pycache__/gui.cpython-38.pyc +0 -0
  314. snappy/__pycache__/horoviewer.cpython-38.pyc +0 -0
  315. snappy/__pycache__/math_basics.cpython-38.pyc +0 -0
  316. snappy/__pycache__/matrix.cpython-38.pyc +0 -0
  317. snappy/__pycache__/number.cpython-38.pyc +0 -0
  318. snappy/__pycache__/numeric_output_checker.cpython-38.pyc +0 -0
  319. snappy/__pycache__/pari.cpython-38.pyc +0 -0
  320. snappy/__pycache__/polyviewer.cpython-38.pyc +0 -0
  321. snappy/__pycache__/sage_helper.cpython-38.pyc +0 -0
  322. snappy/__pycache__/version.cpython-38.pyc +0 -0
  323. snappy/doc/_sources/verify_canon.rst.txt +0 -90
  324. snappy/doc/_static/jquery-3.6.0.js +0 -10881
  325. snappy/doc/_static/js/html5shiv-printshiv.min.js +0 -4
  326. snappy/doc/_static/js/html5shiv.min.js +0 -4
  327. snappy/doc/_static/underscore-1.13.1.js +0 -2042
  328. snappy/doc/_static/underscore.js +0 -6
  329. snappy/doc/verify_canon.html +0 -304
  330. snappy/drilling/__pycache__/__init__.cpython-38.pyc +0 -0
  331. snappy/drilling/__pycache__/constants.cpython-38.pyc +0 -0
  332. snappy/drilling/__pycache__/crush.cpython-38.pyc +0 -0
  333. snappy/drilling/__pycache__/cusps.cpython-38.pyc +0 -0
  334. snappy/drilling/__pycache__/debug.cpython-38.pyc +0 -0
  335. snappy/drilling/__pycache__/epsilons.cpython-38.pyc +0 -0
  336. snappy/drilling/__pycache__/exceptions.cpython-38.pyc +0 -0
  337. snappy/drilling/__pycache__/fixed_points.cpython-38.pyc +0 -0
  338. snappy/drilling/__pycache__/geodesic_info.cpython-38.pyc +0 -0
  339. snappy/drilling/__pycache__/geodesic_tube.cpython-38.pyc +0 -0
  340. snappy/drilling/__pycache__/geometric_structure.cpython-38.pyc +0 -0
  341. snappy/drilling/__pycache__/line.cpython-38.pyc +0 -0
  342. snappy/drilling/__pycache__/moves.cpython-38.pyc +0 -0
  343. snappy/drilling/__pycache__/peripheral_curves.cpython-38.pyc +0 -0
  344. snappy/drilling/__pycache__/perturb.cpython-38.pyc +0 -0
  345. snappy/drilling/__pycache__/quotient_space.cpython-38.pyc +0 -0
  346. snappy/drilling/__pycache__/spatial_dict.cpython-38.pyc +0 -0
  347. snappy/drilling/__pycache__/subdivide.cpython-38.pyc +0 -0
  348. snappy/drilling/__pycache__/tracing.cpython-38.pyc +0 -0
  349. snappy/drilling/geodesic_tube.py +0 -441
  350. snappy/drilling/geometric_structure.py +0 -366
  351. snappy/drilling/line.py +0 -122
  352. snappy/drilling/quotient_space.py +0 -94
  353. snappy/drilling/spatial_dict.py +0 -128
  354. snappy/exterior_to_link/__pycache__/__init__.cpython-38.pyc +0 -0
  355. snappy/exterior_to_link/__pycache__/barycentric_geometry.cpython-38.pyc +0 -0
  356. snappy/exterior_to_link/__pycache__/exceptions.cpython-38.pyc +0 -0
  357. snappy/exterior_to_link/__pycache__/hyp_utils.cpython-38.pyc +0 -0
  358. snappy/exterior_to_link/__pycache__/link_projection.cpython-38.pyc +0 -0
  359. snappy/exterior_to_link/__pycache__/main.cpython-38.pyc +0 -0
  360. snappy/exterior_to_link/__pycache__/mcomplex_with_expansion.cpython-38.pyc +0 -0
  361. snappy/exterior_to_link/__pycache__/mcomplex_with_link.cpython-38.pyc +0 -0
  362. snappy/exterior_to_link/__pycache__/mcomplex_with_memory.cpython-38.pyc +0 -0
  363. snappy/exterior_to_link/__pycache__/pl_utils.cpython-38.pyc +0 -0
  364. snappy/exterior_to_link/__pycache__/put_in_S3.cpython-38.pyc +0 -0
  365. snappy/exterior_to_link/__pycache__/rational_linear_algebra.cpython-38.pyc +0 -0
  366. snappy/exterior_to_link/__pycache__/simplify_to_base_tri.cpython-38.pyc +0 -0
  367. snappy/exterior_to_link/__pycache__/stored_moves.cpython-38.pyc +0 -0
  368. snappy/hyperboloid/__pycache__/__init__.cpython-38.pyc +0 -0
  369. snappy/manifolds/__pycache__/__init__.cpython-38.pyc +0 -0
  370. snappy/ptolemy/__pycache__/__init__.cpython-38.pyc +0 -0
  371. snappy/ptolemy/__pycache__/component.cpython-38.pyc +0 -0
  372. snappy/ptolemy/__pycache__/coordinates.cpython-38.pyc +0 -0
  373. snappy/ptolemy/__pycache__/fieldExtensions.cpython-38.pyc +0 -0
  374. snappy/ptolemy/__pycache__/findLoops.cpython-38.pyc +0 -0
  375. snappy/ptolemy/__pycache__/homology.cpython-38.pyc +0 -0
  376. snappy/ptolemy/__pycache__/manifoldMethods.cpython-38.pyc +0 -0
  377. snappy/ptolemy/__pycache__/matrix.cpython-38.pyc +0 -0
  378. snappy/ptolemy/__pycache__/numericalSolutionsToGroebnerBasis.cpython-38.pyc +0 -0
  379. snappy/ptolemy/__pycache__/polynomial.cpython-38.pyc +0 -0
  380. snappy/ptolemy/__pycache__/processComponents.cpython-38.pyc +0 -0
  381. snappy/ptolemy/__pycache__/processFileBase.cpython-38.pyc +0 -0
  382. snappy/ptolemy/__pycache__/processFileDispatch.cpython-38.pyc +0 -0
  383. snappy/ptolemy/__pycache__/processMagmaFile.cpython-38.pyc +0 -0
  384. snappy/ptolemy/__pycache__/processRurFile.cpython-38.pyc +0 -0
  385. snappy/ptolemy/__pycache__/ptolemyGeneralizedObstructionClass.cpython-38.pyc +0 -0
  386. snappy/ptolemy/__pycache__/ptolemyObstructionClass.cpython-38.pyc +0 -0
  387. snappy/ptolemy/__pycache__/ptolemyVariety.cpython-38.pyc +0 -0
  388. snappy/ptolemy/__pycache__/ptolemyVarietyPrimeIdealGroebnerBasis.cpython-38.pyc +0 -0
  389. snappy/ptolemy/__pycache__/rur.cpython-38.pyc +0 -0
  390. snappy/ptolemy/__pycache__/solutionsToPrimeIdealGroebnerBasis.cpython-38.pyc +0 -0
  391. snappy/ptolemy/__pycache__/utilities.cpython-38.pyc +0 -0
  392. snappy/snap/__pycache__/__init__.cpython-38.pyc +0 -0
  393. snappy/snap/__pycache__/character_varieties.cpython-38.pyc +0 -0
  394. snappy/snap/__pycache__/fundamental_polyhedron.cpython-38.pyc +0 -0
  395. snappy/snap/__pycache__/interval_reps.cpython-38.pyc +0 -0
  396. snappy/snap/__pycache__/kernel_structures.cpython-38.pyc +0 -0
  397. snappy/snap/__pycache__/mcomplex_base.cpython-38.pyc +0 -0
  398. snappy/snap/__pycache__/nsagetools.cpython-38.pyc +0 -0
  399. snappy/snap/__pycache__/polished_reps.cpython-38.pyc +0 -0
  400. snappy/snap/__pycache__/shapes.cpython-38.pyc +0 -0
  401. snappy/snap/__pycache__/slice_obs_HKL.cpython-38.pyc +0 -0
  402. snappy/snap/__pycache__/utilities.cpython-38.pyc +0 -0
  403. snappy/snap/peripheral/__pycache__/__init__.cpython-38.pyc +0 -0
  404. snappy/snap/peripheral/__pycache__/dual_cellulation.cpython-38.pyc +0 -0
  405. snappy/snap/peripheral/__pycache__/link.cpython-38.pyc +0 -0
  406. snappy/snap/peripheral/__pycache__/peripheral.cpython-38.pyc +0 -0
  407. snappy/snap/peripheral/__pycache__/surface.cpython-38.pyc +0 -0
  408. snappy/snap/t3mlite/__pycache__/__init__.cpython-38.pyc +0 -0
  409. snappy/snap/t3mlite/__pycache__/arrow.cpython-38.pyc +0 -0
  410. snappy/snap/t3mlite/__pycache__/corner.cpython-38.pyc +0 -0
  411. snappy/snap/t3mlite/__pycache__/edge.cpython-38.pyc +0 -0
  412. snappy/snap/t3mlite/__pycache__/face.cpython-38.pyc +0 -0
  413. snappy/snap/t3mlite/__pycache__/files.cpython-38.pyc +0 -0
  414. snappy/snap/t3mlite/__pycache__/homology.cpython-38.pyc +0 -0
  415. snappy/snap/t3mlite/__pycache__/linalg.cpython-38.pyc +0 -0
  416. snappy/snap/t3mlite/__pycache__/mcomplex.cpython-38.pyc +0 -0
  417. snappy/snap/t3mlite/__pycache__/perm4.cpython-38.pyc +0 -0
  418. snappy/snap/t3mlite/__pycache__/simplex.cpython-38.pyc +0 -0
  419. snappy/snap/t3mlite/__pycache__/spun.cpython-38.pyc +0 -0
  420. snappy/snap/t3mlite/__pycache__/surface.cpython-38.pyc +0 -0
  421. snappy/snap/t3mlite/__pycache__/tetrahedron.cpython-38.pyc +0 -0
  422. snappy/snap/t3mlite/__pycache__/vertex.cpython-38.pyc +0 -0
  423. snappy/togl/__init__.py +0 -3
  424. snappy/togl/darwin-tk8.6/Togl2.1/LICENSE +0 -28
  425. snappy/togl/darwin-tk8.6/Togl2.1/libTogl2.1.dylib +0 -0
  426. snappy/togl/darwin-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  427. snappy/togl/darwin-tk8.7/Togl2.1/LICENSE +0 -28
  428. snappy/togl/darwin-tk8.7/Togl2.1/libTogl2.1.dylib +0 -0
  429. snappy/togl/darwin-tk8.7/Togl2.1/pkgIndex.tcl +0 -5
  430. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  431. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/libTogl2.1.so +0 -0
  432. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  433. snappy/togl/win32VC-tk8.6/Togl2.1/LICENSE +0 -28
  434. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.dll +0 -0
  435. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.lib +0 -0
  436. snappy/togl/win32VC-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  437. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  438. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.dll +0 -0
  439. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.lib +0 -0
  440. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  441. snappy/twister/__pycache__/__init__.cpython-38.pyc +0 -0
  442. snappy/twister/__pycache__/main.cpython-38.pyc +0 -0
  443. snappy/upper_halfspace/__pycache__/__init__.cpython-38.pyc +0 -0
  444. snappy/upper_halfspace/__pycache__/ideal_point.cpython-38.pyc +0 -0
  445. snappy/verify/__pycache__/__init__.cpython-38.pyc +0 -0
  446. snappy/verify/__pycache__/cuspCrossSection.cpython-38.pyc +0 -0
  447. snappy/verify/__pycache__/cuspTranslations.cpython-38.pyc +0 -0
  448. snappy/verify/__pycache__/cusp_areas.cpython-38.pyc +0 -0
  449. snappy/verify/__pycache__/cusp_shapes.cpython-38.pyc +0 -0
  450. snappy/verify/__pycache__/exceptions.cpython-38.pyc +0 -0
  451. snappy/verify/__pycache__/interval_newton_shapes_engine.cpython-38.pyc +0 -0
  452. snappy/verify/__pycache__/interval_tree.cpython-38.pyc +0 -0
  453. snappy/verify/__pycache__/krawczyk_shapes_engine.cpython-38.pyc +0 -0
  454. snappy/verify/__pycache__/realAlgebra.cpython-38.pyc +0 -0
  455. snappy/verify/__pycache__/shapes.cpython-38.pyc +0 -0
  456. snappy/verify/__pycache__/short_slopes.cpython-38.pyc +0 -0
  457. snappy/verify/__pycache__/squareExtensions.cpython-38.pyc +0 -0
  458. snappy/verify/__pycache__/verifyCanonical.cpython-38.pyc +0 -0
  459. snappy/verify/__pycache__/verifyHyperbolicity.cpython-38.pyc +0 -0
  460. snappy/verify/__pycache__/volume.cpython-38.pyc +0 -0
  461. snappy/verify/complex_volume/__pycache__/__init__.cpython-38.pyc +0 -0
  462. snappy/verify/complex_volume/__pycache__/adjust_torsion.cpython-38.pyc +0 -0
  463. snappy/verify/complex_volume/__pycache__/closed.cpython-38.pyc +0 -0
  464. snappy/verify/complex_volume/__pycache__/compute_ptolemys.cpython-38.pyc +0 -0
  465. snappy/verify/complex_volume/__pycache__/cusped.cpython-38.pyc +0 -0
  466. snappy/verify/complex_volume/__pycache__/extended_bloch.cpython-38.pyc +0 -0
  467. snappy/verify/cuspCrossSection.py +0 -1422
  468. snappy/verify/maximal_cusp_area_matrix/__pycache__/__init__.cpython-38.pyc +0 -0
  469. snappy/verify/maximal_cusp_area_matrix/__pycache__/cusp_tiling_engine.cpython-38.pyc +0 -0
  470. snappy/verify/maximal_cusp_area_matrix/__pycache__/cusp_translate_engine.cpython-38.pyc +0 -0
  471. snappy/verify/upper_halfspace/__pycache__/__init__.cpython-38.pyc +0 -0
  472. snappy/verify/upper_halfspace/__pycache__/extended_matrix.cpython-38.pyc +0 -0
  473. snappy/verify/upper_halfspace/__pycache__/finite_point.cpython-38.pyc +0 -0
  474. snappy/verify/upper_halfspace/__pycache__/ideal_point.cpython-38.pyc +0 -0
  475. snappy-3.1.1.dist-info/RECORD +0 -575
  476. {snappy-3.1.1.dist-info → snappy-3.2.dist-info}/entry_points.txt +0 -0
@@ -1,1422 +0,0 @@
1
- # Original source:
2
- # Asymmetric hyperbolic L-spaces, Heegaard genus, and Dehn filling
3
- # Nathan M. Dunfield, Neil R. Hoffman, Joan E. Licata
4
- # http://arxiv.org/abs/1407.7827
5
- # This code is copyrighted by Nathan Dunfield, Neil Hoffman, and Joan Licata
6
- # and released under the GNU GPL version 2 or (at your option) any later
7
- # version.
8
- #
9
- # 02/22/15 Major rewrite and checked into SnapPy repository:
10
- # handle any number of cusps,
11
- # agnostic of type of numbers for shape,
12
- # support non-orientable manifolds,
13
- # refactoring and cleanup
14
- # - Matthias Goerner
15
- #
16
- # 01/15/16 Split CuspCrossSectionClass into a base class and
17
- # two subclasses for computing real and
18
- # complex edge lengths. Added methods to ensure a cusp
19
- # neighborhood is disjoint and methods to compute the
20
- # complex edge length.
21
- #
22
- # 01/28/18 Fix an important bug: do not use built-in min for intervals.
23
-
24
- from ..sage_helper import _within_sage
25
-
26
- import math
27
-
28
- if _within_sage:
29
- # python's log and sqrt only work for floats
30
- # They would fail or convert to float losing precision
31
- from sage.functions.log import log
32
- from sage.functions.other import sqrt
33
- else:
34
- # Otherwise, define our own log and sqrt which checks whether
35
- # the given type defines a log/sqrt method and fallsback
36
- # to python's log and sqrt which has the above drawback of
37
- # potentially losing precision.
38
- import cmath
39
-
40
- def log(x):
41
- if hasattr(x, 'log'):
42
- return x.log()
43
- return cmath.log(x)
44
-
45
- def sqrt(x):
46
- if hasattr(x, 'sqrt'):
47
- return x.sqrt()
48
- return math.sqrt(x)
49
-
50
- from ..snap import t3mlite as t3m
51
- from ..snap.kernel_structures import *
52
- from ..snap.mcomplex_base import *
53
-
54
- from ..math_basics import correct_min
55
- from .exceptions import *
56
-
57
- __all__ = [
58
- 'IncompleteCuspError',
59
- 'RealCuspCrossSection',
60
- 'ComplexCuspCrossSection']
61
-
62
-
63
- class IncompleteCuspError(RuntimeError):
64
- """
65
- Exception raised when trying to construct a CuspCrossSection
66
- from a Manifold with Dehn-fillings.
67
- """
68
- def __init__(self, manifold):
69
- self.manifold = manifold
70
-
71
- def __str__(self):
72
- return (('Cannot construct CuspCrossSection from manifold with '
73
- 'Dehn-fillings: %s') % self.manifold)
74
-
75
-
76
- class HoroTriangleBase:
77
- @staticmethod
78
- def _make_second(sides, x):
79
- """
80
- Cyclically rotate sides = (a,b,c) so that x is the second entry"
81
- """
82
- i = (sides.index(x) + 2) % len(sides)
83
- return sides[i:]+sides[:i]
84
-
85
- @staticmethod
86
- def _sides_and_cross_ratios(tet, vertex, side):
87
- sides = t3m.simplex.FacesAroundVertexCounterclockwise[vertex]
88
- left_side, center_side, right_side = (
89
- HoroTriangleBase._make_second(sides, side))
90
- z_left = tet.ShapeParameters[left_side & center_side ]
91
- z_right = tet.ShapeParameters[center_side & right_side ]
92
- return left_side, center_side, right_side, z_left, z_right
93
-
94
-
95
- class RealHoroTriangle:
96
- """
97
- A horosphere cross section in the corner of an ideal tetrahedron.
98
- The sides of the triangle correspond to faces of the tetrahedron.
99
- The lengths stored for the triangle are real.
100
- """
101
- def __init__(self, tet, vertex, known_side, length_of_side):
102
- left_side, center_side, right_side, z_left, z_right = (
103
- HoroTriangleBase._sides_and_cross_ratios(tet, vertex, known_side))
104
-
105
- L = length_of_side
106
- self.lengths = { center_side : L,
107
- left_side : abs(z_left) * L,
108
- right_side : L / abs(z_right) }
109
- a, b, c = self.lengths.values()
110
- self.area = L * L * z_left.imag() / 2
111
-
112
- # Below is the usual formula for circumradius
113
- self.circumradius = a * b * c / (4 * self.area)
114
-
115
- def rescale(self, t):
116
- "Rescales the triangle by a Euclidean dilation"
117
- for face in self.lengths:
118
- self.lengths[face] *= t
119
- self.circumradius *= t
120
- self.area *= t * t
121
-
122
- @staticmethod
123
- def direction_sign():
124
- return +1
125
-
126
-
127
- # Given a vertex, cyclically order the three adjacent faces in
128
- # clockwise fashion. For each face, return the triple (face, edge, next face)
129
- # where edge is adjacent to both faces.
130
- _face_edge_face_triples_for_vertex_link = {
131
- vertex : [ (faces[i], faces[i] & faces[(i+1) % 3], faces[(i+1) % 3])
132
- for i in range(3) ]
133
- for vertex, faces in t3m.simplex.FacesAroundVertexCounterclockwise.items()
134
- }
135
-
136
- # For each vertex, return an edge connected to it
137
- _pick_an_edge_for_vertex = {
138
- vertex : [ edge
139
- for edge in t3m.simplex.OneSubsimplices
140
- if t3m.simplex.is_subset(vertex, edge) ][0]
141
- for vertex in t3m.simplex.ZeroSubsimplices
142
- }
143
-
144
- # For each (vertex, face) pair, pick one of the two edges adjacent
145
- # to both the vertex and face
146
- _pick_an_edge_for_vertex_and_face = {
147
- (vertex, face): [ edge
148
- for edge in t3m.simplex.OneSubsimplices
149
- if (t3m.simplex.is_subset(vertex, edge) and
150
- t3m.simplex.is_subset(edge, face)) ][0]
151
- for vertex in t3m.simplex.ZeroSubsimplices
152
- for face in t3m.simplex.TwoSubsimplices
153
- if t3m.simplex.is_subset(vertex, face)
154
- }
155
-
156
-
157
- class ComplexHoroTriangle:
158
- """
159
- A horosphere cross section in the corner of an ideal tetrahedron.
160
- The sides of the triangle correspond to faces of the tetrahedron.
161
- The lengths stored for the triangle are complex.
162
- """
163
- def __init__(self, tet, vertex, known_side, length_of_side):
164
- left_side, center_side, right_side, z_left, z_right = (
165
- HoroTriangleBase._sides_and_cross_ratios(tet, vertex, known_side))
166
-
167
- L = length_of_side
168
- self.lengths = { center_side : L,
169
- left_side : - z_left * L,
170
- right_side : - L / z_right }
171
- absL = abs(L)
172
- self.area = absL * absL * z_left.imag() / 2
173
-
174
- self._real_lengths_cache = None
175
-
176
- def get_real_lengths(self):
177
- if not self._real_lengths_cache:
178
- self._real_lengths_cache = {
179
- side : abs(length)
180
- for side, length in self.lengths.items() }
181
- return self._real_lengths_cache
182
-
183
- def rescale(self, t):
184
- "Rescales the triangle by a Euclidean dilation"
185
- for face in self.lengths:
186
- self.lengths[face] *= t
187
- self.area *= t * t
188
-
189
- @staticmethod
190
- def direction_sign():
191
- return -1
192
-
193
- def add_vertex_positions(self, vertex, edge, position):
194
- """
195
- Adds a dictionary vertex_positions mapping
196
- an edge (such as t3m.simplex.E01) to complex position
197
- for the vertex of the horotriangle obtained by
198
- intersecting the edge with the horosphere.
199
-
200
- Two of these positions are computed from the one given
201
- using the complex edge lengths. The given vertex and
202
- edge are t3m-style.
203
- """
204
-
205
- self.vertex_positions = {}
206
-
207
- # The three triples
208
- # (face, edge adjacent to face and next face, next face)
209
- # when going around the vertex counter clockwise
210
- vertex_link = _face_edge_face_triples_for_vertex_link[vertex]
211
-
212
- # Find for which of these triples the position is for
213
- for i in range(3):
214
- if edge == vertex_link[i][1]:
215
- break
216
-
217
- # Now go through the triples starting with the one for
218
- # which we have given the vertex position
219
- for j in range(3):
220
- face0, edge, face1 = vertex_link[(i + j) % 3]
221
- # Assign vertex position
222
- self.vertex_positions[edge] = position
223
- # Update vertex position to be for the next
224
- # edge using complex edge length
225
- position += self.lengths[face1]
226
-
227
- def lift_vertex_positions(self, lifted_position):
228
- """
229
- Lift the vertex positions of this triangle. lifted_position is
230
- used as a guide what branch of the logarithm to use.
231
-
232
- The lifted position is computed as the log of the vertex
233
- position where it is assumed that the fixed point of the
234
- holonomy is at the origin. The branch of the logarithm
235
- closest to lifted_position is used.
236
- """
237
-
238
- NumericalField = lifted_position.parent()
239
- twoPi = 2 * NumericalField.pi()
240
- I = NumericalField(1j)
241
-
242
- def adjust_log(z):
243
- # Compute log and adjust
244
- logZ = log(z)
245
- # Add multiplies of 2 * pi * I so that it is close
246
- # to lifted_position
247
- return logZ + ((lifted_position - logZ) / twoPi).imag().round() * twoPi * I
248
-
249
- self.lifted_vertex_positions = {
250
- # Take log of vertex position
251
- # (assuming fixed point is at origin).
252
- edge: adjust_log(position)
253
- for edge, position in self.vertex_positions.items()
254
- }
255
-
256
-
257
- class CuspCrossSectionBase(McomplexEngine):
258
- """
259
- Base class for RealCuspCrossSection and ComplexCuspCrossSection.
260
- """
261
-
262
- def add_structures(self, one_cocycle=None):
263
- self._add_edge_dict()
264
- self._add_cusp_cross_sections(one_cocycle)
265
-
266
- def _add_edge_dict(self):
267
- """
268
- Adds a dictionary that maps a pair of vertices to all edges
269
- of the triangulation connecting these vertices.
270
- The key is a pair (v0, v1) of integers with v0 < v1 that are the
271
- indices of the two vertices.
272
- """
273
-
274
- self._edge_dict = {}
275
- for edge in self.mcomplex.Edges:
276
- vert0, vert1 = edge.Vertices
277
- key = tuple(sorted([vert0.Index, vert1.Index]))
278
- self._edge_dict.setdefault(key, []).append(edge)
279
-
280
- def _add_cusp_cross_sections(self, one_cocycle):
281
- for T in self.mcomplex.Tetrahedra:
282
- T.horotriangles = {
283
- t3m.simplex.V0 : None,
284
- t3m.simplex.V1 : None,
285
- t3m.simplex.V2 : None,
286
- t3m.simplex.V3 : None
287
- }
288
- for cusp in self.mcomplex.Vertices:
289
- self._add_one_cusp_cross_section(cusp, one_cocycle)
290
-
291
- def _add_one_cusp_cross_section(self, cusp, one_cocycle):
292
- """
293
- Build a cusp cross section as described in Section 3.6 of the paper
294
-
295
- Asymmetric hyperbolic L-spaces, Heegaard genus, and Dehn filling
296
- Nathan M. Dunfield, Neil R. Hoffman, Joan E. Licata
297
- http://arxiv.org/abs/1407.7827
298
- """
299
- corner0 = cusp.Corners[0]
300
- tet0, vert0 = corner0.Tetrahedron, corner0.Subsimplex
301
- face0 = t3m.simplex.FacesAroundVertexCounterclockwise[vert0][0]
302
- tet0.horotriangles[vert0] = self.HoroTriangle(tet0, vert0, face0, 1)
303
- active = [(tet0, vert0)]
304
- while active:
305
- tet0, vert0 = active.pop()
306
- for face0 in t3m.simplex.FacesAroundVertexCounterclockwise[vert0]:
307
- tet1, face1, vert1 = CuspCrossSectionBase._glued_to(
308
- tet0, face0, vert0)
309
- if tet1.horotriangles[vert1] is None:
310
- known_side = (self.HoroTriangle.direction_sign() *
311
- tet0.horotriangles[vert0].lengths[face0])
312
- if one_cocycle:
313
- known_side *= one_cocycle[tet0.Index, face0, vert0]
314
-
315
- tet1.horotriangles[vert1] = self.HoroTriangle(
316
- tet1, vert1, face1, known_side)
317
- active.append((tet1, vert1))
318
-
319
- @staticmethod
320
- def _glued_to(tetrahedron, face, vertex):
321
- """
322
- Returns (other tet, other face, other vertex).
323
- """
324
- gluing = tetrahedron.Gluing[face]
325
- return tetrahedron.Neighbor[face], gluing.image(face), gluing.image(vertex)
326
-
327
- @staticmethod
328
- def _cusp_area(cusp):
329
- area = 0
330
- for corner in cusp.Corners:
331
- subsimplex = corner.Subsimplex
332
- area += corner.Tetrahedron.horotriangles[subsimplex].area
333
- return area
334
-
335
- def cusp_areas(self):
336
- """
337
- List of all cusp areas.
338
- """
339
- return [ CuspCrossSectionBase._cusp_area(cusp) for cusp in self.mcomplex.Vertices ]
340
-
341
- @staticmethod
342
- def _scale_cusp(cusp, scale):
343
- for corner in cusp.Corners:
344
- subsimplex = corner.Subsimplex
345
- corner.Tetrahedron.horotriangles[subsimplex].rescale(scale)
346
-
347
- def scale_cusps(self, scales):
348
- """
349
- Scale each cusp by Euclidean dilation by values in given array.
350
- """
351
- for cusp, scale in zip(self.mcomplex.Vertices, scales):
352
- CuspCrossSectionBase._scale_cusp(cusp, scale)
353
-
354
- def normalize_cusps(self, areas=None):
355
- """
356
- Scale cusp so that they have the given target area.
357
- Without argument, each cusp is scaled to have area 1.
358
- If the argument is a number, scale each cusp to have that area.
359
- If the argument is an array, scale each cusp by the respective
360
- entry in the array.
361
- """
362
- current_areas = self.cusp_areas()
363
- if not areas:
364
- areas = [ 1 for area in current_areas ]
365
- elif not isinstance(areas, list):
366
- areas = [ areas for area in current_areas ]
367
- scales = [ sqrt(area / current_area)
368
- for area, current_area in zip(areas, current_areas) ]
369
- self.scale_cusps(scales)
370
-
371
- def check_cusp_development_exactly(self):
372
- """
373
- Check that all side lengths of horo triangles are consistent.
374
- If the logarithmic edge equations are fulfilled, this implices
375
- that the all cusps are complete and thus the manifold is complete.
376
- """
377
-
378
- for tet0 in self.mcomplex.Tetrahedra:
379
- for vert0 in t3m.simplex.ZeroSubsimplices:
380
- for face0 in t3m.simplex.FacesAroundVertexCounterclockwise[vert0]:
381
- tet1, face1, vert1 = CuspCrossSectionBase._glued_to(
382
- tet0, face0, vert0)
383
- side0 = tet0.horotriangles[vert0].lengths[face0]
384
- side1 = tet1.horotriangles[vert1].lengths[face1]
385
- if not side0 == side1 * self.HoroTriangle.direction_sign():
386
- raise CuspDevelopmentExactVerifyError(side0, side1)
387
-
388
- @staticmethod
389
- def _shape_for_edge_embedding(tet, perm):
390
- """
391
- Given an edge embedding, find the shape assignment for it.
392
- If the edge embedding flips orientation, apply conjugate inverse.
393
- """
394
-
395
- # Get the shape for this edge embedding
396
- subsimplex = perm.image(3)
397
-
398
- # Figure out the orientation of this tetrahedron
399
- # with respect to the edge, apply conjugate inverse
400
- # if differ
401
- if perm.sign():
402
- return 1 / tet.ShapeParameters[subsimplex].conjugate()
403
- else:
404
- return tet.ShapeParameters[subsimplex]
405
-
406
- def check_polynomial_edge_equations_exactly(self):
407
- """
408
- Check that the polynomial edge equations are fulfilled exactly.
409
-
410
- We use the conjugate inverse to support non-orientable manifolds.
411
- """
412
-
413
- # For each edge
414
- for edge in self.mcomplex.Edges:
415
- # The exact value when evaluating the edge equation
416
- val = 1
417
-
418
- # Iterate through edge embeddings
419
- for tet, perm in edge.embeddings():
420
- # Accumulate shapes of the edge exactly
421
- val *= CuspCrossSectionBase._shape_for_edge_embedding(
422
- tet, perm)
423
-
424
- if not val == 1:
425
- raise EdgeEquationExactVerifyError(val)
426
-
427
- def check_logarithmic_edge_equations_and_positivity(self, NumericalField):
428
- """
429
- Check that the shapes have positive imaginary part and that the
430
- logarithmic gluing equations have small error.
431
-
432
- The shapes are coerced into the field given as argument before the
433
- logarithm is computed. It can be, e.g., a ComplexIntervalField.
434
- """
435
-
436
- # For each edge
437
- for edge in self.mcomplex.Edges:
438
-
439
- # The complex interval arithmetic value of the logarithmic
440
- # version of the edge equation.
441
- log_sum = 0
442
-
443
- # Iterate through edge embeddings
444
- for tet, perm in edge.embeddings():
445
-
446
- shape = CuspCrossSectionBase._shape_for_edge_embedding(
447
- tet, perm)
448
-
449
- numerical_shape = NumericalField(shape)
450
-
451
- log_shape = log(numerical_shape)
452
-
453
- # Note that this is true for z in R, R < 0 as well,
454
- # but then it would fail for 1 - 1/z or 1 / (1-z)
455
-
456
- if not (log_shape.imag() > 0):
457
- raise ShapePositiveImaginaryPartNumericalVerifyError(
458
- numerical_shape)
459
-
460
- # Take logarithm and accumulate
461
- log_sum += log_shape
462
-
463
- twoPiI = NumericalField.pi() * NumericalField(2j)
464
-
465
- if not abs(log_sum - twoPiI) < NumericalField(1e-7):
466
- raise EdgeEquationLogLiftNumericalVerifyError(log_sum)
467
-
468
- def _testing_check_against_snappea(self, epsilon):
469
- # Short-hand
470
- ZeroSubs = t3m.simplex.ZeroSubsimplices
471
-
472
- # SnapPea kernel results
473
- snappea_tilts, snappea_edges = self.manifold._cusp_cross_section_info()
474
-
475
- # Check edge lengths
476
- # Iterate through tet
477
- for tet, snappea_tet_edges in zip(self.mcomplex.Tetrahedra, snappea_edges):
478
- # Iterate through vertices of tet
479
- for v, snappea_triangle_edges in zip(ZeroSubs, snappea_tet_edges):
480
- # Iterate through faces touching that vertex
481
- for f, snappea_triangle_edge in zip(ZeroSubs,
482
- snappea_triangle_edges):
483
- if v != f:
484
- F = t3m.simplex.comp(f)
485
- length = abs(tet.horotriangles[v].lengths[F])
486
- if not abs(length - snappea_triangle_edge) < epsilon:
487
- raise ConsistencyWithSnapPeaNumericalVerifyError(
488
- snappea_triangle_edge, length)
489
-
490
- @staticmethod
491
- def _lower_bound_max_area_triangle_for_std_form(z):
492
- """
493
- Imagine an ideal tetrahedron in the upper half space model with
494
- vertices at 0, 1, z, and infinity. Pick the lowest (horizontal)
495
- horosphere about infinity that intersects the tetrahedron in a
496
- triangle, i.e, just touches the face opposite to infinity.
497
- This method will return the hyperbolic area of that triangle.
498
-
499
- The result is the same for z, 1/(1-z), and 1 - 1/z.
500
- """
501
-
502
- # First, we check whether the center of the circumcenter of the
503
- # triangle containing 0, 1, and z is contained within the triangle.
504
-
505
- # If the center is outside of the triangle, the Euclidean height of the
506
- # horosphere is that of the highest point of the three arcs between
507
- # 0, 1, and z.
508
- # The height is half of the length e of the longest edge of the
509
- # triangle.
510
- # Given that the Euclidean area of the triangle is given by
511
- # A = Im(z) / 2, its hyperbolic area is
512
- # A / (e/2)^2 = Im(z) / 2 / (e^2/4) = 2 * Im(z) / e^2
513
- #
514
- # This is similar to fef_gen.py except that it had a bug in version 1.3
515
- # and implemented the last inequality the other way around!
516
- #
517
- # The center is outside if one of the angles is > pi/2, cover each case
518
- #
519
-
520
- # Angle at 0 is > pi/2
521
- if z.real() < 0:
522
- # So longest edge of the triangle must be opposite of 0
523
- return 2 * z.imag() / (abs(z - 1) ** 2)
524
- # Angle at 1 is > pi/2
525
- if z.real() > 1:
526
- # So longest edge of the triangle must be opposite of 1
527
- return 2 * z.imag() / (abs(z) ** 2)
528
- # Angle at z is > pi/2
529
- if abs(2 * z - 1) < 1:
530
- # So longest edge of the triangle must be opposite of z
531
- return 2 * z.imag()
532
-
533
- # An interval note: the circumcenter might still be in the triangle,
534
- # we just were not able to prove it. The area we compute is a lower
535
- # bound in any case. Thus, the function is not guaranteed to compute
536
- # the maximal area, just a lower bound for it.
537
-
538
- # Now cover the case that the center of the triangle is within the
539
- # triangle.
540
-
541
- # The Euclidean area of the above triangle is given by
542
- # A = Im(z) / 2
543
- # and its Euclidean side lengths are given by
544
- # a = 1, b = abs(z), and c = abs(z - 1).
545
- #
546
- # The Euclidean circumradius r of the triangle is given by the usual
547
- # formula
548
- # r = a * b * c / (4 * A)
549
- #
550
- # This is also the Euclidean radius of the circle containing 0, 1, and
551
- # z and of the halfsphere above that circle that contains the face
552
- # opposite to infinity.
553
- # Therefore, r is also the Euclidean height of the above horosphere and
554
- # hence, the hyperbolic metric at that height is 1/r.
555
- # So the hyperbolic area of the triangle becomes
556
- #
557
- # A / r^2 = A / (a * b * c / (4 * A))^2 = 16 * A^3 / (a * b * c)^2
558
- # = 2 * Im(z)^3 / (abs(z) * abs(z-1)) ^ 2
559
-
560
- return 2 * z.imag() ** 3 / (abs(z) * abs(z - 1)) ** 2
561
-
562
- def ensure_std_form(self, allow_scaling_up=False):
563
- """
564
- Makes sure that the cusp neighborhoods intersect each tetrahedron
565
- in standard form by scaling the cusp neighborhoods down if necessary.
566
- """
567
-
568
- z = self.mcomplex.Tetrahedra[0].ShapeParameters[t3m.simplex.E01]
569
- RF = z.real().parent()
570
-
571
- # For each cusp, save the scaling factors for all triangles so that
572
- # we can later take the minimum to scale each cusp.
573
- if allow_scaling_up:
574
- area_scales = [ [] for v in self.mcomplex.Vertices ]
575
- else:
576
- # Add 1 so that we never scale the cusp area up, just down.
577
- area_scales = [ [RF(1)] for v in self.mcomplex.Vertices ]
578
-
579
- for tet in self.mcomplex.Tetrahedra:
580
- # Compute maximal area of a triangle for standard form
581
- z = tet.ShapeParameters[t3m.simplex.E01]
582
- max_area = ComplexCuspCrossSection._lower_bound_max_area_triangle_for_std_form(z)
583
-
584
- # For all four triangles corresponding to the four vertices of the
585
- # tetrahedron
586
- for zeroSubsimplex, triangle in tet.horotriangles.items():
587
- # Compute the area scaling factor
588
- area_scale = max_area / triangle.area
589
- # Get the cusp we need to scale
590
- vertex = tet.Class[zeroSubsimplex]
591
- # Remember it
592
- area_scales[vertex.Index].append(area_scale)
593
-
594
- # Compute scale per cusp as sqrt of the minimum of all area scales
595
- # of all triangles in that cusp
596
- scales = [ sqrt(correct_min(s)) for s in area_scales ]
597
-
598
- self.scale_cusps(scales)
599
-
600
- @staticmethod
601
- def _exp_distance_edge(edge):
602
- """
603
- Given an edge, returns the exp of the (hyperbolic) distance of the
604
- two cusp neighborhoods at the ends of the edge measured along that
605
- edge.
606
- """
607
-
608
- # Get one embedding of the edge, tet is adjacent to that edge
609
- tet, perm = next(edge.embeddings())
610
- # Get a face of the tetrahedron adjacent to that edge
611
- face = 15 - (1 << perm[3])
612
- # At each end of the edge, this tetrahedron gives us one
613
- # triangle of a cusp cross-section and the intersection of the
614
- # face with the cusp cross-section gives us one edge of the
615
- # triangle.
616
- # Multiply the two edge lengths. If these are complex edge
617
- # lengths, the result is actually the square of a Ptolemy
618
- # coordinate (see C. Zickert, The volume and Chern-Simons
619
- # invariant of a representation).
620
- ptolemy_sqr = (tet.horotriangles[1 << perm[0]].lengths[face] *
621
- tet.horotriangles[1 << perm[1]].lengths[face])
622
- # Take abs value in case we have complex edge lengths.
623
- return abs(1 / ptolemy_sqr)
624
-
625
- @staticmethod
626
- def _exp_distance_of_edges(edges):
627
- """
628
- Given edges between two (not necessarily distinct) cusps,
629
- compute the exp of the smallest (hyperbolic) distance of the
630
- two cusp neighborhoods measured along all the given edges.
631
- """
632
- return correct_min(
633
- [ ComplexCuspCrossSection._exp_distance_edge(edge)
634
- for edge in edges])
635
-
636
- def ensure_disjoint_on_edges(self):
637
- """
638
- Scales the cusp neighborhoods down until they are disjoint when
639
- intersected with the edges of the triangulations.
640
-
641
- Given an edge of a triangulation, we can easily compute the signed
642
- distance between the two cusp neighborhoods at the ends of the edge
643
- measured along that edge. Thus, we can easily check that all the
644
- distances measured along all the edges are positive and scale the
645
- cusps down if necessary.
646
-
647
- Unfortunately, this is not sufficient to ensure that two cusp
648
- neighborhoods are disjoint since there might be a geodesic between
649
- the two cusps such that the distance between the two cusps measured
650
- along the geodesic is shorter than measured along any edge of the
651
- triangulation.
652
-
653
- Thus, it is necessary to call ensure_std_form as well:
654
- it will make sure that the cusp neighborhoods are small enough so
655
- that they intersect the tetrahedra in "standard" form.
656
- Here, "standard" form means that the corresponding horoball about a
657
- vertex of a tetrahedron intersects the three faces of the tetrahedron
658
- adjacent to the vertex but not the one opposite to the vertex.
659
-
660
- For any geometric triangulation, standard form and positive distance
661
- measured along all edges of the triangulation is sufficient for
662
- disjoint neighborhoods.
663
-
664
- The SnapPea kernel uses the proto-canonical triangulation associated
665
- to the cusp neighborhood to get around this when computing the
666
- "reach" and the "stoppers" for the cusps.
667
-
668
- **Remark:** This means that the cusp neighborhoods might be scaled down
669
- more than necessary. Related open questions are: given maximal disjoint
670
- cusp neighborhoods (maximal in the sense that no neighborhood can be
671
- expanded without bumping into another or itself), is there always a
672
- geometric triangulation intersecting the cusp neighborhoods in standard
673
- form? Is there an easy algorithm to find this triangulation, e.g., by
674
- applying a 2-3 move whenever we see a non-standard intersection?
675
- """
676
-
677
- num_cusps = len(self.mcomplex.Vertices)
678
-
679
- # First check for every cusp that its cusp neighborhood does not bump
680
- # into itself - at least when measured along the edges of the
681
- # triangulation
682
- for i in range(num_cusps):
683
- # Get all edges
684
- if (i,i) in self._edge_dict:
685
- dist = ComplexCuspCrossSection._exp_distance_of_edges(
686
- self._edge_dict[(i,i)])
687
- # For verified computations, do not use the seemingly
688
- # equivalent dist <= 1. We want to scale down every time
689
- # we cannot ensure they are disjoint.
690
- if not (dist > 1):
691
- scale = sqrt(dist)
692
- # Scale the one cusp
693
- ComplexCuspCrossSection._scale_cusp(self.mcomplex.Vertices[i],
694
- scale)
695
-
696
- # Now check for the pairs of two distinct cusps that the corresponding
697
- # neighborhoods do not bump into each other - at least when measured
698
- # along the edges of the triangulation
699
- for i in range(num_cusps):
700
- for j in range(i):
701
- # Get all edges
702
- if (j,i) in self._edge_dict:
703
- dist = ComplexCuspCrossSection._exp_distance_of_edges(
704
- self._edge_dict[(j,i)])
705
- # Above comment applies
706
- if not (dist > 1):
707
- # Scale the two cusps by the same amount
708
- # We have choices here, for example, we could only
709
- # scale one cusp by dist.
710
- scale = sqrt(dist)
711
- ComplexCuspCrossSection._scale_cusp(self.mcomplex.Vertices[i],
712
- scale)
713
- ComplexCuspCrossSection._scale_cusp(self.mcomplex.Vertices[j],
714
- scale)
715
-
716
-
717
- class RealCuspCrossSection(CuspCrossSectionBase):
718
- """
719
- A t3m triangulation with real edge lengths of cusp cross sections built
720
- from a cusped (possibly non-orientable) SnapPy manifold M with a hyperbolic
721
- structure specified by shapes. It can scale the cusps to areas that can be
722
- specified or scale them such that they are disjoint.
723
- It can also compute the "tilts" used in the Tilt Theorem, see
724
- ``canonize_part_1.c``.
725
-
726
- The computations are agnostic about the type of numbers provided as shapes
727
- as long as they provide ``+``, ``-``, ``*``, ``/``, ``conjugate()``,
728
- ``im()``, ``abs()``, ``sqrt()``.
729
- Shapes can be a numerical type such as ComplexIntervalField or an exact
730
- type (supporting sqrt) such as QQbar.
731
-
732
- The resulting edge lengths and tilts will be of the type returned by
733
- applying the above operations to the shapes. For example, if the shapes
734
- are in ComplexIntervalField, the edge lengths and tilts are elements in
735
- RealIntervalField.
736
-
737
- **Remark:** The real edge lengths could also be obtained from the complex
738
- edge lengths computed by ``ComplexCuspCrossSection``, but this has two
739
- drawbacks. The times at which we apply ``abs`` or ``sqrt`` during the
740
- development and rescaling of the cusps would be different. Though this
741
- gives the same values, the resulting representation of these values by an
742
- exact number type (such as the ones in ``squareExtension.py``) might be
743
- prohibitively more complicated. Furthermore, ``ComplexCuspCrossSection``
744
- does not work for non-orientable manifolds (it does not implement working
745
- in a cusp's double-cover like the SnapPea kernel does).
746
- """
747
-
748
- HoroTriangle = RealHoroTriangle
749
-
750
- @staticmethod
751
- def fromManifoldAndShapes(manifold, shapes):
752
- """
753
- **Examples:**
754
-
755
- Initialize from shapes provided from the floats returned by
756
- tetrahedra_shapes. The tilts appear to be negative but are not
757
- verified by interval arithmetics::
758
-
759
- >>> from snappy import Manifold
760
- >>> M = Manifold("m004")
761
- >>> M.canonize()
762
- >>> shapes = M.tetrahedra_shapes('rect')
763
- >>> e = RealCuspCrossSection.fromManifoldAndShapes(M, shapes)
764
- >>> e.normalize_cusps()
765
- >>> e.compute_tilts()
766
- >>> tilts = e.read_tilts()
767
- >>> for tilt in tilts:
768
- ... print('%.8f' % tilt)
769
- -0.31020162
770
- -0.31020162
771
- -0.31020162
772
- -0.31020162
773
- -0.31020162
774
- -0.31020162
775
- -0.31020162
776
- -0.31020162
777
-
778
- Use verified intervals:
779
-
780
- sage: from snappy.verify import *
781
- sage: M = Manifold("m004")
782
- sage: M.canonize()
783
- sage: shapes = M.tetrahedra_shapes('rect', intervals=True)
784
-
785
- Verify that the tetrahedra shapes form a complete manifold:
786
-
787
- sage: check_logarithmic_gluing_equations_and_positively_oriented_tets(M,shapes)
788
- sage: e = RealCuspCrossSection.fromManifoldAndShapes(M, shapes)
789
- sage: e.normalize_cusps()
790
- sage: e.compute_tilts()
791
-
792
-
793
- Tilts are verified to be negative:
794
-
795
- sage: [tilt < 0 for tilt in e.read_tilts()]
796
- [True, True, True, True, True, True, True, True]
797
-
798
- Setup necessary things in Sage:
799
-
800
- sage: from sage.rings.qqbar import QQbar
801
- sage: from sage.rings.rational_field import RationalField
802
- sage: from sage.rings.polynomial.polynomial_ring import polygen
803
- sage: from sage.rings.real_mpfi import RealIntervalField
804
- sage: from sage.rings.complex_interval_field import ComplexIntervalField
805
- sage: x = polygen(RationalField())
806
- sage: RIF = RealIntervalField()
807
- sage: CIF = ComplexIntervalField()
808
-
809
- sage: M = Manifold("m412")
810
- sage: M.canonize()
811
-
812
- Make our own exact shapes using Sage. They are the root of the given
813
- polynomial isolated by the given interval.
814
-
815
- sage: r=QQbar.polynomial_root(x**2-x+1,CIF(RIF(0.49,0.51),RIF(0.86,0.87)))
816
- sage: shapes = 5 * [r]
817
- sage: e=RealCuspCrossSection.fromManifoldAndShapes(M, shapes)
818
- sage: e.normalize_cusps()
819
-
820
- The following three lines verify that we have shapes giving a complete
821
- hyperbolic structure. The last one uses complex interval arithmetics.
822
-
823
- sage: e.check_polynomial_edge_equations_exactly()
824
- sage: e.check_cusp_development_exactly()
825
- sage: e.check_logarithmic_edge_equations_and_positivity(CIF)
826
-
827
- Because we use exact types, we can verify that each tilt is either
828
- negative or exactly zero.
829
-
830
- sage: e.compute_tilts()
831
- sage: [(tilt < 0, tilt == 0) for tilt in e.read_tilts()]
832
- [(True, False), (True, False), (False, True), (True, False), (True, False), (True, False), (True, False), (False, True), (True, False), (True, False), (True, False), (False, True), (False, True), (False, True), (False, True), (False, True), (True, False), (True, False), (False, True), (True, False)]
833
-
834
- Some are exactly zero, so the canonical cell decomposition has
835
- non-tetrahedral cells. In fact, the one cell is a cube. We can obtain
836
- the retriangulation of the canonical cell decomposition as follows:
837
-
838
- sage: e.compute_tilts()
839
- sage: opacities = [tilt < 0 for tilt in e.read_tilts()]
840
- sage: N = M._canonical_retriangulation()
841
- sage: N.num_tetrahedra()
842
- 12
843
-
844
- The manifold m412 has 8 isometries, the above code certified that using
845
- exact arithmetic:
846
- sage: len(N.isomorphisms_to(N))
847
- 8
848
- """
849
- for cusp_info in manifold.cusp_info():
850
- if not cusp_info['complete?']:
851
- raise IncompleteCuspError(manifold)
852
-
853
- m = t3m.Mcomplex(manifold)
854
-
855
- t = TransferKernelStructuresEngine(m, manifold)
856
- t.reindex_cusps_and_transfer_peripheral_curves()
857
- t.add_shapes(shapes)
858
-
859
- c = RealCuspCrossSection(m)
860
- c.add_structures()
861
-
862
- # For testing against SnapPea kernel data
863
- c.manifold = manifold
864
-
865
- return c
866
-
867
- @staticmethod
868
- def _tet_tilt(tet, face):
869
- "The tilt of the face of the tetrahedron."
870
-
871
- v = t3m.simplex.comp(face)
872
-
873
- ans = 0
874
- for w in t3m.simplex.ZeroSubsimplices:
875
- if v == w:
876
- c_w = 1
877
- else:
878
- z = tet.ShapeParameters[v | w]
879
- c_w = -z.real() / abs(z)
880
- R_w = tet.horotriangles[w].circumradius
881
- ans += c_w * R_w
882
- return ans
883
-
884
- @staticmethod
885
- def _face_tilt(face):
886
- """
887
- Tilt of a face in the trinagulation: this is the sum of
888
- the two tilts of the two faces of the two tetrahedra that are
889
- glued. The argument is a t3m.simplex.Face.
890
- """
891
-
892
- return sum([ RealCuspCrossSection._tet_tilt(corner.Tetrahedron,
893
- corner.Subsimplex)
894
- for corner in face.Corners ])
895
-
896
- def compute_tilts(self):
897
- """
898
- Computes all tilts. They are written to the instances of
899
- t3m.simplex.Face and can be accessed as
900
- [ face.Tilt for face in crossSection.Faces].
901
- """
902
-
903
- for face in self.mcomplex.Faces:
904
- face.Tilt = RealCuspCrossSection._face_tilt(face)
905
-
906
- def read_tilts(self):
907
- """
908
- After compute_tilts() has been called, put the tilt values into an
909
- array containing the tilt of face 0, 1, 2, 3 of the first tetrahedron,
910
- ... of the second tetrahedron, ....
911
- """
912
-
913
- def index_of_face_corner(corner):
914
- face_index = t3m.simplex.comp(corner.Subsimplex).bit_length() - 1
915
- return 4 * corner.Tetrahedron.Index + face_index
916
-
917
- tilts = (4 * len(self.mcomplex.Tetrahedra)) * [ None ]
918
-
919
- # For each face of the triangulation
920
- for face in self.mcomplex.Faces:
921
- for corner in face.Corners:
922
- tilts[index_of_face_corner(corner)] = face.Tilt
923
-
924
- return tilts
925
-
926
- def _testing_check_against_snappea(self, epsilon):
927
- """
928
- Compare the computed edge lengths and tilts against the one computed by
929
- the SnapPea kernel.
930
-
931
- >>> from snappy import Manifold
932
-
933
- Convention of the kernel is to use (3/8) sqrt(3) as area (ensuring that
934
- cusp neighborhoods are disjoint).
935
-
936
- >>> cusp_area = 0.649519052838329
937
-
938
- >>> for name in ['m009', 'm015', 't02333']:
939
- ... M = Manifold(name)
940
- ... e = RealCuspCrossSection.fromManifoldAndShapes(M, M.tetrahedra_shapes('rect'))
941
- ... e.normalize_cusps(cusp_area)
942
- ... e._testing_check_against_snappea(1e-10)
943
-
944
- """
945
-
946
- CuspCrossSectionBase._testing_check_against_snappea(self, epsilon)
947
-
948
- # Short-hand
949
- TwoSubs = t3m.simplex.TwoSubsimplices
950
-
951
- # SnapPea kernel results
952
- snappea_tilts, snappea_edges = self.manifold._cusp_cross_section_info()
953
-
954
- # Check tilts
955
- # Iterate through tet
956
- for tet, snappea_tet_tilts in zip(self.mcomplex.Tetrahedra, snappea_tilts):
957
- # Iterate through vertices of tet
958
- for f, snappea_tet_tilt in zip(TwoSubs, snappea_tet_tilts):
959
- tilt = RealCuspCrossSection._tet_tilt(tet, f)
960
- if not abs(snappea_tet_tilt - tilt) < epsilon:
961
- raise ConsistencyWithSnapPeaNumericalVerifyError(
962
- snappea_tet_tilt, tilt)
963
-
964
-
965
- class ComplexCuspCrossSection(CuspCrossSectionBase):
966
- """
967
- Similarly to RealCuspCrossSection with the following differences: it
968
- computes the complex edge lengths and the cusp translations (instead
969
- of the tilts) and it only works for orientable manifolds.
970
-
971
- The same comment applies about the type of the shapes. The resulting
972
- edge lengths and translations will be of the same type as the shapes.
973
-
974
- For shapes corresponding to a non-boundary unipotent representation
975
- (in other words, a manifold having an incomplete cusp), a cusp can
976
- be developed if an appropriate 1-cocycle is given. The 1-cocycle
977
- is a cellular cocycle in the dual of the cusp triangulations and
978
- represents an element in H^1(boundary M; C^*) that must match the
979
- PSL(2,C) boundary holonomy of the representation.
980
- It is encoded as dictionary with key (tet index, t3m face, t3m vertex).
981
- """
982
-
983
- HoroTriangle = ComplexHoroTriangle
984
-
985
- @staticmethod
986
- def fromManifoldAndShapes(manifold, shapes, one_cocycle=None):
987
- if not one_cocycle:
988
- for cusp_info in manifold.cusp_info():
989
- if not cusp_info['complete?']:
990
- raise IncompleteCuspError(manifold)
991
-
992
- if not manifold.is_orientable():
993
- raise ValueError("Non-orientable")
994
-
995
- m = t3m.Mcomplex(manifold)
996
-
997
- t = TransferKernelStructuresEngine(m, manifold)
998
- t.reindex_cusps_and_transfer_peripheral_curves()
999
- t.add_shapes(shapes)
1000
-
1001
- if one_cocycle == 'develop':
1002
- resolved_one_cocycle = None
1003
- else:
1004
- resolved_one_cocycle = one_cocycle
1005
-
1006
- c = ComplexCuspCrossSection(m)
1007
- c.add_structures(resolved_one_cocycle)
1008
-
1009
- # For testing against SnapPea kernel data
1010
- c.manifold = manifold
1011
-
1012
- return c
1013
-
1014
- def _dummy_for_testing(self):
1015
- """
1016
- Compare the computed edge lengths and tilts against the one computed by
1017
- the SnapPea kernel.
1018
-
1019
- >>> from snappy import Manifold
1020
-
1021
- Convention of the kernel is to use (3/8) sqrt(3) as area (ensuring that
1022
- cusp neighborhoods are disjoint).
1023
-
1024
- >>> cusp_area = 0.649519052838329
1025
-
1026
- >>> for name in ['m009', 'm015', 't02333']:
1027
- ... M = Manifold(name)
1028
- ... e = ComplexCuspCrossSection.fromManifoldAndShapes(M, M.tetrahedra_shapes('rect'))
1029
- ... e.normalize_cusps(cusp_area)
1030
- ... e._testing_check_against_snappea(1e-10)
1031
-
1032
- """
1033
-
1034
- @staticmethod
1035
- def _get_translation(vertex, ml):
1036
- """
1037
- Compute the translation corresponding to the meridian (ml = 0) or
1038
- longitude (ml = 1) of the given cusp.
1039
- """
1040
-
1041
- # Accumulate result
1042
- result = 0
1043
-
1044
- # For each triangle of this cusp's cross-section
1045
- for corner in vertex.Corners:
1046
- # Get the corresponding tetrahedron
1047
- tet = corner.Tetrahedron
1048
- # Get the corresponding vertex of this tetrahedron
1049
- subsimplex = corner.Subsimplex
1050
- # Get the three faces of the tetrahedron adjacent to that vertex
1051
- # Each one intersects the cusp cross-section in an edge of
1052
- # the triangle.
1053
- faces = t3m.simplex.FacesAroundVertexCounterclockwise[subsimplex]
1054
- # Get the data for this triangle
1055
- triangle = tet.horotriangles[subsimplex]
1056
-
1057
- # Restrict the peripheral curve data to this triangle.
1058
- # The result consists of four integers, but the one at
1059
- # subsimplex will always be zero, so effectively, it
1060
- # is three integers corresponding to the three sides of the
1061
- # triangle.
1062
- # Each of these integers tells us how often the peripheral curve
1063
- # "enters" the triangle from the corresponding side of the
1064
- # triangle.
1065
- # Each time the peripheral curve "enters" the triangle through a
1066
- # side, its contribution to the translation is the vector from the
1067
- # center of the side to the center of the triangle.
1068
- curves = tet.PeripheralCurves[ml][0][subsimplex]
1069
-
1070
- # We know need to compute this contribution to the translation.
1071
- # Imagine a triangle with complex edge lengths e_0, e_1, e_2 and,
1072
- # without loss of generality, move it such that its vertices are
1073
- # at v_0 = 0, v_1 = e_0, v_2 = e_0 + e_1.
1074
- # The center of the triangle is at
1075
- # c = (v_0 + v_1 + v_2) / 3 = 2 * e_0 / 3 + e_1 / 3.
1076
- # The vector from the center of the side corresponding to e_0
1077
- # to the center of the triangle is given by
1078
- # c - e_0 / 2 = e_0 / 6 + e_1 / 3
1079
- #
1080
- # If the peripheral curves enters the side of the triangle
1081
- # corresponding to e_i n_i-times, then the total contribution
1082
- # with respect to that triangle is given by
1083
- # n_0 * (e_0 / 6 + e_1 / 3)
1084
- # + n_1 * (e_1 / 6 + e_2 / 3)
1085
- # + n_2 * (e_2 / 6 + e_0 / 3)
1086
- # = ( (n_0 + 2 * n_2) * e_0
1087
- # + (n_1 + 2 * n_0) * e_1
1088
- # + (n_2 + 2 * n_1) * e_2) / 6
1089
- #
1090
- # = (sum_{i=0,1,2} (n_i + 2 * n_{i+2}) * e_i) / 6
1091
-
1092
- # Implement this sum
1093
- for i in range(3):
1094
- # Find the t3m faces corresponding to two edges of this
1095
- # triangle
1096
- this_face = faces[ i ]
1097
- prev_face = faces[(i+2) % 3]
1098
-
1099
- # n_i + 2 * n_{i+2} in above notation
1100
- f = curves[this_face] + 2 * curves[prev_face]
1101
-
1102
- # (n_i + 2 * n_{i+2}) * e_i in above notation
1103
- result += f * triangle.lengths[this_face]
1104
-
1105
- return result / 6
1106
-
1107
- @staticmethod
1108
- def _compute_translations(vertex):
1109
- vertex.Translations = [
1110
- ComplexCuspCrossSection._get_translation(vertex, i)
1111
- for i in range(2) ]
1112
-
1113
- def compute_translations(self):
1114
- for vertex in self.mcomplex.Vertices:
1115
- ComplexCuspCrossSection._compute_translations(vertex)
1116
-
1117
- @staticmethod
1118
- def _get_normalized_translations(vertex):
1119
- """
1120
- Compute the translations corresponding to the merdian and longitude of
1121
- the given cusp.
1122
- """
1123
-
1124
- m, l = vertex.Translations
1125
- return m / l * abs(l), abs(l)
1126
-
1127
- def all_normalized_translations(self):
1128
- """
1129
- Compute the translations corresponding to the meridian and longitude
1130
- for each cusp.
1131
- """
1132
-
1133
- self.compute_translations()
1134
- return [ ComplexCuspCrossSection._get_normalized_translations(vertex)
1135
- for vertex in self.mcomplex.Vertices ]
1136
-
1137
- @staticmethod
1138
- def _compute_cusp_shape(vertex):
1139
- m, l = vertex.Translations
1140
- return (l / m).conjugate()
1141
-
1142
- def cusp_shapes(self):
1143
- """
1144
- Compute the cusp shapes as conjugate of the quotient of the translations
1145
- corresponding to the longitude and meridian for each cusp (SnapPea
1146
- kernel convention).
1147
- """
1148
- self.compute_translations()
1149
- return [ ComplexCuspCrossSection._compute_cusp_shape(vertex)
1150
- for vertex in self.mcomplex.Vertices ]
1151
-
1152
- def add_vertex_positions_to_horotriangles(self):
1153
- """
1154
- Develops cusp to assign to each horotriangle the positions of its three
1155
- vertices in the Euclidean plane.
1156
-
1157
- Note: For a complete cusp, this is defined only up to translating the
1158
- entire triangle by translations generated by meridian and longitude.
1159
-
1160
- For an incomplete cusp, this is defined only up to
1161
- similarities generated by the meridian and longitude. The
1162
- positions can be moved such that the fixed point of these
1163
- similarities is at the origin by calling
1164
- move_fixed_point_to_zero after
1165
- add_vertex_positions_to_horotriangles.
1166
-
1167
- Note: This is not working when one_cocycle is passed during the
1168
- construction of the cusp cross section.
1169
- """
1170
- for cusp in self.mcomplex.Vertices:
1171
- self._add_one_cusp_vertex_positions(cusp)
1172
-
1173
- def _add_one_cusp_vertex_positions(self, cusp):
1174
- """
1175
- Procedure is similar to _add_one_cusp_cross_section
1176
- """
1177
-
1178
- corner0 = cusp.Corners[0]
1179
- tet0, vert0 = corner0.Tetrahedron, corner0.Subsimplex
1180
- zero = tet0.ShapeParameters[t3m.simplex.E01].parent()(0)
1181
- tet0.horotriangles[vert0].add_vertex_positions(
1182
- vert0, _pick_an_edge_for_vertex[vert0], zero)
1183
-
1184
- active = [(tet0, vert0)]
1185
-
1186
- # Pairs (tet index, vertex) indicating what has already been
1187
- # visited
1188
- visited = set()
1189
-
1190
- while active:
1191
- tet0, vert0 = active.pop()
1192
- for face0 in t3m.simplex.FacesAroundVertexCounterclockwise[vert0]:
1193
- tet1, face1, vert1 = CuspCrossSectionBase._glued_to(
1194
- tet0, face0, vert0)
1195
- if not (tet1.Index, vert1) in visited:
1196
- edge0 = _pick_an_edge_for_vertex_and_face[vert0, face0]
1197
- edge1 = tet0.Gluing[face0].image(edge0)
1198
-
1199
- tet1.horotriangles[vert1].add_vertex_positions(
1200
- vert1,
1201
- edge1,
1202
- tet0.horotriangles[vert0].vertex_positions[edge0])
1203
-
1204
- active.append( (tet1, vert1) )
1205
- visited.add((tet1.Index, vert1))
1206
-
1207
- def _debug_show_horotriangles(self, cusp=0):
1208
- from sage.all import line, real, imag
1209
-
1210
- self.add_vertex_positions_to_horotriangles()
1211
-
1212
- return sum(
1213
- [ line( [ (real(z0), imag(z0)),
1214
- (real(z1), imag(z1)) ] )
1215
- for tet in self.mcomplex.Tetrahedra
1216
- for V, h in tet.horotriangles.items()
1217
- for z0 in h.vertex_positions.values()
1218
- for z1 in h.vertex_positions.values()
1219
- if tet.Class[V].Index == cusp ])
1220
-
1221
- def _debug_show_lifted_horotriangles(self, cusp=0):
1222
- from sage.all import line, real, imag
1223
-
1224
- self.add_vertex_positions_to_horotriangles()
1225
-
1226
- return sum(
1227
- [ line( [ (real(z0), imag(z0)),
1228
- (real(z1), imag(z1)) ] )
1229
- for tet in self.mcomplex.Tetrahedra
1230
- for V, h in tet.horotriangles.items()
1231
- for z0 in h.lifted_vertex_positions.values()
1232
- for z1 in h.lifted_vertex_positions.values()
1233
- if tet.Class[V].Index == cusp ])
1234
-
1235
- def move_fixed_point_to_zero(self):
1236
- """
1237
- Determines the fixed point of the holonomies for all
1238
- incomplete cusps. Then moves the vertex positions of the
1239
- corresponding cusp triangles so that the fixed point is at the
1240
- origin.
1241
-
1242
- It also add the boolean v.is_complete to all vertices of the
1243
- triangulation to mark whether the corresponding cusp is
1244
- complete or not.
1245
- """
1246
-
1247
- # For each cusp
1248
- for cusp, cusp_info in zip(self.mcomplex.Vertices,
1249
- self.manifold.cusp_info()):
1250
-
1251
- cusp.is_complete = cusp_info['complete?']
1252
- if not cusp.is_complete:
1253
- # For an incomplete cusp, compute fixed point
1254
- fixed_pt = self._compute_cusp_fixed_point(cusp)
1255
- for corner in cusp.Corners:
1256
- tet, vert = corner.Tetrahedron, corner.Subsimplex
1257
- trig = tet.horotriangles[vert]
1258
- # Move all vertex positions so that fixed point
1259
- # is at origin
1260
- trig.vertex_positions = {
1261
- edge : position - fixed_pt
1262
- for edge, position in trig.vertex_positions.items() }
1263
-
1264
- def _compute_cusp_fixed_point(self, cusp):
1265
- """
1266
- Compute fixed point for an incomplete cusp.
1267
- """
1268
-
1269
- # Given a horotriangle trig0 with a vertex and edge, let
1270
- # l0 be the complex position of the vertex and p0 the complex
1271
- # edge length.
1272
- # Let trig1 be the horotriangle glued to trig0 along the edge
1273
- # and the l1 and p1 be the corresponding position and edge length
1274
- # (traversed the opposite direction) in the other horotriangle.
1275
- #
1276
- # Then the similarity is described the complex number z = -l1 / l0
1277
- # which is one or the holonomy of meridian or longitude (depending
1278
- # on whether the common edge is inside or on the boundary of a
1279
- # fundamental domain implicitly chosen when developing the cusp).
1280
- #
1281
- # Furthermore, we can compute the fixed point p of the similarity
1282
- # using p1 - p = z * (p0 - p).
1283
-
1284
- # Compute z, p0, p1 for each horotriangle, vertex and edge and pick
1285
- # the one where z is furthest away from one.
1286
- dummy, z, p0, p1 = max(self._compute_cusp_fixed_point_data(cusp),
1287
- key=lambda d: d[0])
1288
-
1289
- # Compute fixed point
1290
- return (p1 - z * p0) / (1 - z)
1291
-
1292
- def _compute_cusp_fixed_point_data(self, cusp):
1293
- """
1294
- Compute abs(z-1), z, p0, p1 for each horotriangle, vertex and edge
1295
- as described in _compute_cusp_fixed_point.
1296
- """
1297
-
1298
- # For each horotriangle
1299
- for corner in cusp.Corners:
1300
- tet0, vert0 = corner.Tetrahedron, corner.Subsimplex
1301
- vertex_link = _face_edge_face_triples_for_vertex_link[vert0]
1302
-
1303
- # A flag of a horotriangle corresponds to a face and edge
1304
- # of the tetrahedron.
1305
- for face0, edge0, other_face in vertex_link:
1306
- # How that horotriangle is glued to the neighboring one
1307
- tet1, face1, vert1 = CuspCrossSectionBase._glued_to(
1308
- tet0, face0, vert0)
1309
- edge1 = tet0.Gluing[face0].image(edge0)
1310
-
1311
- # Get horotriangle and the complex vertex position and
1312
- # edge length
1313
- trig0 = tet0.horotriangles[vert0]
1314
- l0 = trig0.lengths[face0]
1315
- p0 = trig0.vertex_positions[edge0]
1316
-
1317
- # And for neighbor
1318
- trig1 = tet1.horotriangles[vert1]
1319
- l1 = trig1.lengths[face1]
1320
- p1 = trig1.vertex_positions[edge1]
1321
-
1322
- # Parameter for similarity
1323
- z = - l1 / l0
1324
- yield (abs(z - 1), z, p0, p1)
1325
-
1326
- def lift_vertex_positions_of_horotriangles(self):
1327
- """
1328
- After developing an incomplete cusp with
1329
- add_vertex_positions_to_horotriangles, this function moves the
1330
- vertex positions first to zero the fixed point (see
1331
- move_ffixed_point_to_zero) and computes logarithms for all the
1332
- vertex positions of the horotriangles in the Euclidean plane
1333
- in a consistent manner. These logarithms are written to a
1334
- dictionary lifted_vertex_positions on the HoroTriangle's.
1335
-
1336
- For an incomplete cusp, the respective value in lifted_vertex_positions
1337
- will be None.
1338
-
1339
- The three logarithms of the vertex positions of a triangle are only
1340
- defined up to adding mu Z + lambda Z where mu and lambda are the
1341
- logarithmic holonomies of the meridian and longitude.
1342
- """
1343
-
1344
- self.move_fixed_point_to_zero()
1345
-
1346
- for cusp in self.mcomplex.Vertices:
1347
- self._lift_one_cusp_vertex_positions(cusp)
1348
-
1349
- def _lift_one_cusp_vertex_positions(self, cusp):
1350
- # Pick first triangle to develop
1351
- corner0 = cusp.Corners[0]
1352
- tet0, vert0 = corner0.Tetrahedron, corner0.Subsimplex
1353
- trig0 = tet0.horotriangles[vert0]
1354
- edge0 = _pick_an_edge_for_vertex[vert0]
1355
-
1356
- if cusp.is_complete:
1357
- # If cusp is complete, we store None for the logarithms
1358
- for corner in cusp.Corners:
1359
- tet0, vert0 = corner.Tetrahedron, corner.Subsimplex
1360
- tet0.horotriangles[vert0].lifted_vertex_positions = {
1361
- vert0 | vert1 : None
1362
- for vert1 in t3m.ZeroSubsimplices
1363
- if vert0 != vert1 }
1364
- return
1365
-
1366
- # Lift first triangle, picking main branch of logarithm for
1367
- # the first vertex
1368
- trig0.lift_vertex_positions(log(trig0.vertex_positions[edge0]))
1369
-
1370
- # Procedure similar to _add_one_cusp_cross_section
1371
- active = [(tet0, vert0)]
1372
-
1373
- # Pairs (tet index, vertex) indicating what has already been
1374
- # visited
1375
- visited = set()
1376
-
1377
- while active:
1378
- tet0, vert0 = active.pop()
1379
- for face0 in t3m.simplex.FacesAroundVertexCounterclockwise[vert0]:
1380
- tet1, face1, vert1 = CuspCrossSectionBase._glued_to(
1381
- tet0, face0, vert0)
1382
- if not (tet1.Index, vert1) in visited:
1383
- edge0 = _pick_an_edge_for_vertex_and_face[vert0, face0]
1384
-
1385
- # Lift triangle using lifted vertex position of
1386
- # neighboring triangle as guide (when determining what
1387
- # branch of logarithm to take).
1388
- tet1.horotriangles[vert1].lift_vertex_positions(
1389
- tet0.horotriangles[vert0].lifted_vertex_positions[edge0])
1390
-
1391
- active.append( (tet1, vert1) )
1392
- visited.add( (tet1.Index, vert1) )
1393
-
1394
- def move_lifted_vertex_positions_to_zero_first(self):
1395
- """
1396
- Shift the lifted vertex positions such that the one associated
1397
- to the first vertex when developing the incomplete cusp is
1398
- zero. This makes the values we obtain more stable when
1399
- changing the Dehn-surgery parameters.
1400
- """
1401
-
1402
- for cusp in self.mcomplex.Vertices:
1403
- if not cusp.is_complete:
1404
- ComplexCuspCrossSection._move_lifted_vertex_positions_cusp(cusp)
1405
-
1406
- @staticmethod
1407
- def _move_lifted_vertex_positions_cusp(cusp):
1408
- corner0 = cusp.Corners[0]
1409
- tet0, vert0 = corner0.Tetrahedron, corner0.Subsimplex
1410
- trig0 = tet0.horotriangles[vert0]
1411
- edge0 = _pick_an_edge_for_vertex[vert0]
1412
-
1413
- log0 = trig0.lifted_vertex_positions[edge0]
1414
-
1415
- for corner in cusp.Corners:
1416
- tet, vert = corner.Tetrahedron, corner.Subsimplex
1417
- trig = tet.horotriangles[vert]
1418
-
1419
- trig.lifted_vertex_positions = {
1420
- edge: position - log0
1421
- for edge, position in trig.lifted_vertex_positions.items()
1422
- }