snappy 3.1.1__cp311-cp311-win_amd64.whl → 3.2__cp311-cp311-win_amd64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (476) hide show
  1. snappy/CyOpenGL.cp311-win_amd64.pyd +0 -0
  2. snappy/SnapPy.cp311-win_amd64.pyd +0 -0
  3. snappy/SnapPyHP.cp311-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.cp311-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 +26 -11
  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-311.pyc +0 -0
  305. snappy/__pycache__/browser.cpython-311.pyc +0 -0
  306. snappy/__pycache__/cache.cpython-311.pyc +0 -0
  307. snappy/__pycache__/database.cpython-311.pyc +0 -0
  308. snappy/__pycache__/db_utilities.cpython-311.pyc +0 -0
  309. snappy/__pycache__/decorated_isosig.cpython-311.pyc +0 -0
  310. snappy/__pycache__/exceptions.cpython-311.pyc +0 -0
  311. snappy/__pycache__/export_stl.cpython-311.pyc +0 -0
  312. snappy/__pycache__/filedialog.cpython-311.pyc +0 -0
  313. snappy/__pycache__/gui.cpython-311.pyc +0 -0
  314. snappy/__pycache__/horoviewer.cpython-311.pyc +0 -0
  315. snappy/__pycache__/math_basics.cpython-311.pyc +0 -0
  316. snappy/__pycache__/matrix.cpython-311.pyc +0 -0
  317. snappy/__pycache__/number.cpython-311.pyc +0 -0
  318. snappy/__pycache__/numeric_output_checker.cpython-311.pyc +0 -0
  319. snappy/__pycache__/pari.cpython-311.pyc +0 -0
  320. snappy/__pycache__/polyviewer.cpython-311.pyc +0 -0
  321. snappy/__pycache__/sage_helper.cpython-311.pyc +0 -0
  322. snappy/__pycache__/version.cpython-311.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-311.pyc +0 -0
  331. snappy/drilling/__pycache__/constants.cpython-311.pyc +0 -0
  332. snappy/drilling/__pycache__/crush.cpython-311.pyc +0 -0
  333. snappy/drilling/__pycache__/cusps.cpython-311.pyc +0 -0
  334. snappy/drilling/__pycache__/debug.cpython-311.pyc +0 -0
  335. snappy/drilling/__pycache__/epsilons.cpython-311.pyc +0 -0
  336. snappy/drilling/__pycache__/exceptions.cpython-311.pyc +0 -0
  337. snappy/drilling/__pycache__/fixed_points.cpython-311.pyc +0 -0
  338. snappy/drilling/__pycache__/geodesic_info.cpython-311.pyc +0 -0
  339. snappy/drilling/__pycache__/geodesic_tube.cpython-311.pyc +0 -0
  340. snappy/drilling/__pycache__/geometric_structure.cpython-311.pyc +0 -0
  341. snappy/drilling/__pycache__/line.cpython-311.pyc +0 -0
  342. snappy/drilling/__pycache__/moves.cpython-311.pyc +0 -0
  343. snappy/drilling/__pycache__/peripheral_curves.cpython-311.pyc +0 -0
  344. snappy/drilling/__pycache__/perturb.cpython-311.pyc +0 -0
  345. snappy/drilling/__pycache__/quotient_space.cpython-311.pyc +0 -0
  346. snappy/drilling/__pycache__/spatial_dict.cpython-311.pyc +0 -0
  347. snappy/drilling/__pycache__/subdivide.cpython-311.pyc +0 -0
  348. snappy/drilling/__pycache__/tracing.cpython-311.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-311.pyc +0 -0
  355. snappy/exterior_to_link/__pycache__/barycentric_geometry.cpython-311.pyc +0 -0
  356. snappy/exterior_to_link/__pycache__/exceptions.cpython-311.pyc +0 -0
  357. snappy/exterior_to_link/__pycache__/hyp_utils.cpython-311.pyc +0 -0
  358. snappy/exterior_to_link/__pycache__/link_projection.cpython-311.pyc +0 -0
  359. snappy/exterior_to_link/__pycache__/main.cpython-311.pyc +0 -0
  360. snappy/exterior_to_link/__pycache__/mcomplex_with_expansion.cpython-311.pyc +0 -0
  361. snappy/exterior_to_link/__pycache__/mcomplex_with_link.cpython-311.pyc +0 -0
  362. snappy/exterior_to_link/__pycache__/mcomplex_with_memory.cpython-311.pyc +0 -0
  363. snappy/exterior_to_link/__pycache__/pl_utils.cpython-311.pyc +0 -0
  364. snappy/exterior_to_link/__pycache__/put_in_S3.cpython-311.pyc +0 -0
  365. snappy/exterior_to_link/__pycache__/rational_linear_algebra.cpython-311.pyc +0 -0
  366. snappy/exterior_to_link/__pycache__/simplify_to_base_tri.cpython-311.pyc +0 -0
  367. snappy/exterior_to_link/__pycache__/stored_moves.cpython-311.pyc +0 -0
  368. snappy/hyperboloid/__pycache__/__init__.cpython-311.pyc +0 -0
  369. snappy/manifolds/__pycache__/__init__.cpython-311.pyc +0 -0
  370. snappy/ptolemy/__pycache__/__init__.cpython-311.pyc +0 -0
  371. snappy/ptolemy/__pycache__/component.cpython-311.pyc +0 -0
  372. snappy/ptolemy/__pycache__/coordinates.cpython-311.pyc +0 -0
  373. snappy/ptolemy/__pycache__/fieldExtensions.cpython-311.pyc +0 -0
  374. snappy/ptolemy/__pycache__/findLoops.cpython-311.pyc +0 -0
  375. snappy/ptolemy/__pycache__/homology.cpython-311.pyc +0 -0
  376. snappy/ptolemy/__pycache__/manifoldMethods.cpython-311.pyc +0 -0
  377. snappy/ptolemy/__pycache__/matrix.cpython-311.pyc +0 -0
  378. snappy/ptolemy/__pycache__/numericalSolutionsToGroebnerBasis.cpython-311.pyc +0 -0
  379. snappy/ptolemy/__pycache__/polynomial.cpython-311.pyc +0 -0
  380. snappy/ptolemy/__pycache__/processComponents.cpython-311.pyc +0 -0
  381. snappy/ptolemy/__pycache__/processFileBase.cpython-311.pyc +0 -0
  382. snappy/ptolemy/__pycache__/processFileDispatch.cpython-311.pyc +0 -0
  383. snappy/ptolemy/__pycache__/processMagmaFile.cpython-311.pyc +0 -0
  384. snappy/ptolemy/__pycache__/processRurFile.cpython-311.pyc +0 -0
  385. snappy/ptolemy/__pycache__/ptolemyGeneralizedObstructionClass.cpython-311.pyc +0 -0
  386. snappy/ptolemy/__pycache__/ptolemyObstructionClass.cpython-311.pyc +0 -0
  387. snappy/ptolemy/__pycache__/ptolemyVariety.cpython-311.pyc +0 -0
  388. snappy/ptolemy/__pycache__/ptolemyVarietyPrimeIdealGroebnerBasis.cpython-311.pyc +0 -0
  389. snappy/ptolemy/__pycache__/rur.cpython-311.pyc +0 -0
  390. snappy/ptolemy/__pycache__/solutionsToPrimeIdealGroebnerBasis.cpython-311.pyc +0 -0
  391. snappy/ptolemy/__pycache__/utilities.cpython-311.pyc +0 -0
  392. snappy/snap/__pycache__/__init__.cpython-311.pyc +0 -0
  393. snappy/snap/__pycache__/character_varieties.cpython-311.pyc +0 -0
  394. snappy/snap/__pycache__/fundamental_polyhedron.cpython-311.pyc +0 -0
  395. snappy/snap/__pycache__/interval_reps.cpython-311.pyc +0 -0
  396. snappy/snap/__pycache__/kernel_structures.cpython-311.pyc +0 -0
  397. snappy/snap/__pycache__/mcomplex_base.cpython-311.pyc +0 -0
  398. snappy/snap/__pycache__/nsagetools.cpython-311.pyc +0 -0
  399. snappy/snap/__pycache__/polished_reps.cpython-311.pyc +0 -0
  400. snappy/snap/__pycache__/shapes.cpython-311.pyc +0 -0
  401. snappy/snap/__pycache__/slice_obs_HKL.cpython-311.pyc +0 -0
  402. snappy/snap/__pycache__/utilities.cpython-311.pyc +0 -0
  403. snappy/snap/peripheral/__pycache__/__init__.cpython-311.pyc +0 -0
  404. snappy/snap/peripheral/__pycache__/dual_cellulation.cpython-311.pyc +0 -0
  405. snappy/snap/peripheral/__pycache__/link.cpython-311.pyc +0 -0
  406. snappy/snap/peripheral/__pycache__/peripheral.cpython-311.pyc +0 -0
  407. snappy/snap/peripheral/__pycache__/surface.cpython-311.pyc +0 -0
  408. snappy/snap/t3mlite/__pycache__/__init__.cpython-311.pyc +0 -0
  409. snappy/snap/t3mlite/__pycache__/arrow.cpython-311.pyc +0 -0
  410. snappy/snap/t3mlite/__pycache__/corner.cpython-311.pyc +0 -0
  411. snappy/snap/t3mlite/__pycache__/edge.cpython-311.pyc +0 -0
  412. snappy/snap/t3mlite/__pycache__/face.cpython-311.pyc +0 -0
  413. snappy/snap/t3mlite/__pycache__/files.cpython-311.pyc +0 -0
  414. snappy/snap/t3mlite/__pycache__/homology.cpython-311.pyc +0 -0
  415. snappy/snap/t3mlite/__pycache__/linalg.cpython-311.pyc +0 -0
  416. snappy/snap/t3mlite/__pycache__/mcomplex.cpython-311.pyc +0 -0
  417. snappy/snap/t3mlite/__pycache__/perm4.cpython-311.pyc +0 -0
  418. snappy/snap/t3mlite/__pycache__/simplex.cpython-311.pyc +0 -0
  419. snappy/snap/t3mlite/__pycache__/spun.cpython-311.pyc +0 -0
  420. snappy/snap/t3mlite/__pycache__/surface.cpython-311.pyc +0 -0
  421. snappy/snap/t3mlite/__pycache__/tetrahedron.cpython-311.pyc +0 -0
  422. snappy/snap/t3mlite/__pycache__/vertex.cpython-311.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-311.pyc +0 -0
  442. snappy/twister/__pycache__/main.cpython-311.pyc +0 -0
  443. snappy/upper_halfspace/__pycache__/__init__.cpython-311.pyc +0 -0
  444. snappy/upper_halfspace/__pycache__/ideal_point.cpython-311.pyc +0 -0
  445. snappy/verify/__pycache__/__init__.cpython-311.pyc +0 -0
  446. snappy/verify/__pycache__/cuspCrossSection.cpython-311.pyc +0 -0
  447. snappy/verify/__pycache__/cuspTranslations.cpython-311.pyc +0 -0
  448. snappy/verify/__pycache__/cusp_areas.cpython-311.pyc +0 -0
  449. snappy/verify/__pycache__/cusp_shapes.cpython-311.pyc +0 -0
  450. snappy/verify/__pycache__/exceptions.cpython-311.pyc +0 -0
  451. snappy/verify/__pycache__/interval_newton_shapes_engine.cpython-311.pyc +0 -0
  452. snappy/verify/__pycache__/interval_tree.cpython-311.pyc +0 -0
  453. snappy/verify/__pycache__/krawczyk_shapes_engine.cpython-311.pyc +0 -0
  454. snappy/verify/__pycache__/realAlgebra.cpython-311.pyc +0 -0
  455. snappy/verify/__pycache__/shapes.cpython-311.pyc +0 -0
  456. snappy/verify/__pycache__/short_slopes.cpython-311.pyc +0 -0
  457. snappy/verify/__pycache__/squareExtensions.cpython-311.pyc +0 -0
  458. snappy/verify/__pycache__/verifyCanonical.cpython-311.pyc +0 -0
  459. snappy/verify/__pycache__/verifyHyperbolicity.cpython-311.pyc +0 -0
  460. snappy/verify/__pycache__/volume.cpython-311.pyc +0 -0
  461. snappy/verify/complex_volume/__pycache__/__init__.cpython-311.pyc +0 -0
  462. snappy/verify/complex_volume/__pycache__/adjust_torsion.cpython-311.pyc +0 -0
  463. snappy/verify/complex_volume/__pycache__/closed.cpython-311.pyc +0 -0
  464. snappy/verify/complex_volume/__pycache__/compute_ptolemys.cpython-311.pyc +0 -0
  465. snappy/verify/complex_volume/__pycache__/cusped.cpython-311.pyc +0 -0
  466. snappy/verify/complex_volume/__pycache__/extended_bloch.cpython-311.pyc +0 -0
  467. snappy/verify/cuspCrossSection.py +0 -1422
  468. snappy/verify/maximal_cusp_area_matrix/__pycache__/__init__.cpython-311.pyc +0 -0
  469. snappy/verify/maximal_cusp_area_matrix/__pycache__/cusp_tiling_engine.cpython-311.pyc +0 -0
  470. snappy/verify/maximal_cusp_area_matrix/__pycache__/cusp_translate_engine.cpython-311.pyc +0 -0
  471. snappy/verify/upper_halfspace/__pycache__/__init__.cpython-311.pyc +0 -0
  472. snappy/verify/upper_halfspace/__pycache__/extended_matrix.cpython-311.pyc +0 -0
  473. snappy/verify/upper_halfspace/__pycache__/finite_point.cpython-311.pyc +0 -0
  474. snappy/verify/upper_halfspace/__pycache__/ideal_point.cpython-311.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
- }