snappy 3.0.3__cp38-cp38-macosx_11_0_arm64.whl → 3.2__cp38-cp38-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (401) hide show
  1. snappy/CyOpenGL.cpython-38-darwin.so +0 -0
  2. snappy/SnapPy.cpython-38-darwin.so +0 -0
  3. snappy/SnapPyHP.cpython-38-darwin.so +0 -0
  4. snappy/__init__.py +373 -426
  5. snappy/app.py +240 -75
  6. snappy/app_menus.py +93 -78
  7. snappy/browser.py +87 -63
  8. snappy/cache.py +5 -8
  9. snappy/canonical.py +249 -0
  10. snappy/{verify/cusp_shapes.py → cusps/__init__.py} +11 -19
  11. snappy/cusps/cusp_area_matrix.py +101 -0
  12. snappy/{verify/cusp_areas.py → cusps/cusp_areas_from_matrix.py} +39 -54
  13. snappy/cusps/maximal_cusp_area_matrix.py +136 -0
  14. snappy/cusps/test.py +21 -0
  15. snappy/cusps/trig_cusp_area_matrix.py +63 -0
  16. snappy/database.py +40 -31
  17. snappy/db_utilities.py +13 -14
  18. snappy/decorated_isosig.py +377 -133
  19. snappy/dev/extended_ptolemy/complexVolumesClosed.py +42 -9
  20. snappy/dev/extended_ptolemy/extended.py +32 -25
  21. snappy/dev/extended_ptolemy/giac_rur.py +23 -8
  22. snappy/dev/extended_ptolemy/phc_wrapper.py +10 -10
  23. snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +2 -1
  24. snappy/dev/vericlosed/gimbalLoopFinder.py +5 -5
  25. snappy/dev/vericlosed/hyperbolicStructure.py +3 -3
  26. snappy/dev/vericlosed/oneVertexTruncatedComplex.py +2 -2
  27. snappy/dev/vericlosed/truncatedComplex.py +3 -2
  28. snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +4 -3
  29. snappy/doc/_images/geodesics.jpg +0 -0
  30. snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
  31. snappy/doc/_images/m125_paper_plane.jpg +0 -0
  32. snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
  33. snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
  34. snappy/doc/_sources/additional_classes.rst.txt +1 -0
  35. snappy/doc/_sources/credits.rst.txt +6 -1
  36. snappy/doc/_sources/development.rst.txt +69 -50
  37. snappy/doc/_sources/index.rst.txt +101 -66
  38. snappy/doc/_sources/installing.rst.txt +148 -165
  39. snappy/doc/_sources/news.rst.txt +136 -32
  40. snappy/doc/_sources/ptolemy.rst.txt +1 -1
  41. snappy/doc/_sources/ptolemy_examples1.rst.txt +9 -8
  42. snappy/doc/_sources/ptolemy_examples2.rst.txt +3 -3
  43. snappy/doc/_sources/ptolemy_examples3.rst.txt +14 -14
  44. snappy/doc/_sources/ptolemy_prelim.rst.txt +1 -1
  45. snappy/doc/_sources/snap.rst.txt +2 -2
  46. snappy/doc/_sources/snappy.rst.txt +1 -1
  47. snappy/doc/_sources/triangulation.rst.txt +3 -2
  48. snappy/doc/_sources/verify.rst.txt +89 -29
  49. snappy/doc/_sources/verify_internals.rst.txt +5 -16
  50. snappy/doc/_static/SnapPy-horizontal-128.png +0 -0
  51. snappy/doc/_static/SnapPy.ico +0 -0
  52. snappy/doc/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  53. snappy/doc/_static/basic.css +47 -27
  54. snappy/doc/_static/css/badge_only.css +1 -0
  55. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  56. snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  57. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  58. snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  59. snappy/doc/_static/css/fonts/fontawesome-webfont.eot +0 -0
  60. snappy/doc/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  61. snappy/doc/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  62. snappy/doc/_static/css/fonts/fontawesome-webfont.woff +0 -0
  63. snappy/doc/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  64. snappy/doc/_static/css/fonts/lato-bold-italic.woff +0 -0
  65. snappy/doc/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  66. snappy/doc/_static/css/fonts/lato-bold.woff +0 -0
  67. snappy/doc/_static/css/fonts/lato-bold.woff2 +0 -0
  68. snappy/doc/_static/css/fonts/lato-normal-italic.woff +0 -0
  69. snappy/doc/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  70. snappy/doc/_static/css/fonts/lato-normal.woff +0 -0
  71. snappy/doc/_static/css/fonts/lato-normal.woff2 +0 -0
  72. snappy/doc/_static/css/theme.css +4 -0
  73. snappy/doc/_static/doctools.js +107 -274
  74. snappy/doc/_static/documentation_options.js +6 -5
  75. snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
  76. snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
  77. snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
  78. snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
  79. snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  80. snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  81. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  82. snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  83. snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
  84. snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
  85. snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
  86. snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
  87. snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
  88. snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
  89. snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
  90. snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
  91. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  92. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  93. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  94. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  95. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  96. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  97. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  98. snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  99. snappy/doc/_static/jquery.js +2 -2
  100. snappy/doc/_static/js/badge_only.js +1 -0
  101. snappy/doc/_static/js/theme.js +1 -0
  102. snappy/doc/_static/js/versions.js +228 -0
  103. snappy/doc/_static/language_data.js +3 -101
  104. snappy/doc/_static/pygments.css +1 -0
  105. snappy/doc/_static/searchtools.js +489 -398
  106. snappy/doc/_static/snappy_furo.css +33 -0
  107. snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -0
  108. snappy/doc/_static/sphinx_highlight.js +154 -0
  109. snappy/doc/additional_classes.html +688 -263
  110. snappy/doc/bugs.html +107 -94
  111. snappy/doc/censuses.html +155 -127
  112. snappy/doc/credits.html +115 -104
  113. snappy/doc/development.html +184 -146
  114. snappy/doc/genindex.html +287 -204
  115. snappy/doc/index.html +189 -150
  116. snappy/doc/installing.html +259 -266
  117. snappy/doc/manifold.html +1626 -592
  118. snappy/doc/manifoldhp.html +119 -105
  119. snappy/doc/news.html +198 -104
  120. snappy/doc/objects.inv +0 -0
  121. snappy/doc/other.html +117 -105
  122. snappy/doc/platonic_census.html +161 -114
  123. snappy/doc/plink.html +113 -105
  124. snappy/doc/ptolemy.html +131 -108
  125. snappy/doc/ptolemy_classes.html +242 -223
  126. snappy/doc/ptolemy_examples1.html +144 -130
  127. snappy/doc/ptolemy_examples2.html +141 -129
  128. snappy/doc/ptolemy_examples3.html +148 -132
  129. snappy/doc/ptolemy_examples4.html +131 -111
  130. snappy/doc/ptolemy_prelim.html +162 -138
  131. snappy/doc/py-modindex.html +104 -69
  132. snappy/doc/screenshots.html +117 -108
  133. snappy/doc/search.html +115 -84
  134. snappy/doc/searchindex.js +1 -1
  135. snappy/doc/snap.html +109 -96
  136. snappy/doc/snappy.html +134 -97
  137. snappy/doc/spherogram.html +259 -187
  138. snappy/doc/todo.html +107 -94
  139. snappy/doc/triangulation.html +1380 -111
  140. snappy/doc/tutorial.html +107 -94
  141. snappy/doc/verify.html +194 -125
  142. snappy/doc/verify_internals.html +248 -686
  143. snappy/drilling/__init__.py +456 -0
  144. snappy/drilling/barycentric.py +103 -0
  145. snappy/drilling/constants.py +5 -0
  146. snappy/drilling/crush.py +270 -0
  147. snappy/drilling/cusps.py +125 -0
  148. snappy/drilling/debug.py +242 -0
  149. snappy/drilling/epsilons.py +6 -0
  150. snappy/drilling/exceptions.py +55 -0
  151. snappy/drilling/moves.py +620 -0
  152. snappy/drilling/peripheral_curves.py +210 -0
  153. snappy/drilling/perturb.py +188 -0
  154. snappy/drilling/shorten.py +36 -0
  155. snappy/drilling/subdivide.py +274 -0
  156. snappy/drilling/test.py +23 -0
  157. snappy/drilling/test_cases.py +126 -0
  158. snappy/drilling/tracing.py +351 -0
  159. snappy/exceptions.py +23 -3
  160. snappy/export_stl.py +20 -14
  161. snappy/exterior_to_link/__init__.py +2 -0
  162. snappy/exterior_to_link/barycentric_geometry.py +463 -0
  163. snappy/exterior_to_link/exceptions.py +6 -0
  164. snappy/exterior_to_link/geodesic_map.json +14408 -0
  165. snappy/exterior_to_link/hyp_utils.py +112 -0
  166. snappy/exterior_to_link/link_projection.py +323 -0
  167. snappy/exterior_to_link/main.py +197 -0
  168. snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
  169. snappy/exterior_to_link/mcomplex_with_link.py +687 -0
  170. snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
  171. snappy/exterior_to_link/pl_utils.py +491 -0
  172. snappy/exterior_to_link/put_in_S3.py +156 -0
  173. snappy/exterior_to_link/rational_linear_algebra.py +123 -0
  174. snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
  175. snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
  176. snappy/exterior_to_link/stored_moves.py +475 -0
  177. snappy/exterior_to_link/test.py +31 -0
  178. snappy/geometric_structure/__init__.py +212 -0
  179. snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
  180. snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
  181. snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
  182. snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
  183. snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
  184. snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
  185. snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
  186. snappy/geometric_structure/geodesic/__init__.py +0 -0
  187. snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
  188. snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
  189. snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
  190. snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
  191. snappy/geometric_structure/geodesic/constants.py +6 -0
  192. snappy/geometric_structure/geodesic/exceptions.py +22 -0
  193. snappy/geometric_structure/geodesic/fixed_points.py +93 -0
  194. snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
  195. snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
  196. snappy/geometric_structure/geodesic/line.py +30 -0
  197. snappy/geometric_structure/geodesic/multiplicity.py +127 -0
  198. snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
  199. snappy/geometric_structure/test.py +22 -0
  200. snappy/gui.py +36 -36
  201. snappy/horoviewer.py +50 -48
  202. snappy/hyperboloid/__init__.py +212 -0
  203. snappy/hyperboloid/distances.py +245 -0
  204. snappy/hyperboloid/horoball.py +19 -0
  205. snappy/hyperboloid/line.py +35 -0
  206. snappy/hyperboloid/point.py +9 -0
  207. snappy/hyperboloid/triangle.py +29 -0
  208. snappy/{infodialog.py → infowindow.py} +32 -33
  209. snappy/isometry_signature.py +382 -0
  210. snappy/len_spec/__init__.py +596 -0
  211. snappy/len_spec/geodesic_info.py +110 -0
  212. snappy/len_spec/geodesic_key_info_dict.py +117 -0
  213. snappy/len_spec/geodesic_piece.py +143 -0
  214. snappy/len_spec/geometric_structure.py +182 -0
  215. snappy/len_spec/geometry.py +80 -0
  216. snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
  217. snappy/len_spec/spine.py +206 -0
  218. snappy/len_spec/test.py +24 -0
  219. snappy/len_spec/test_cases.py +69 -0
  220. snappy/len_spec/tile.py +275 -0
  221. snappy/len_spec/word.py +86 -0
  222. snappy/manifolds/__init__.py +1 -1
  223. snappy/math_basics.py +176 -0
  224. snappy/matrix.py +525 -0
  225. snappy/number.py +97 -21
  226. snappy/numeric_output_checker.py +37 -27
  227. snappy/pari.py +30 -69
  228. snappy/phone_home.py +25 -20
  229. snappy/polyviewer.py +39 -37
  230. snappy/ptolemy/__init__.py +4 -6
  231. snappy/ptolemy/component.py +14 -12
  232. snappy/ptolemy/coordinates.py +312 -295
  233. snappy/ptolemy/fieldExtensions.py +14 -12
  234. snappy/ptolemy/findLoops.py +43 -31
  235. snappy/ptolemy/geometricRep.py +24 -26
  236. snappy/ptolemy/homology.py +12 -7
  237. snappy/ptolemy/manifoldMethods.py +69 -70
  238. snappy/ptolemy/matrix.py +65 -26
  239. snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +18 -14
  240. snappy/ptolemy/polynomial.py +125 -119
  241. snappy/ptolemy/processComponents.py +36 -30
  242. snappy/ptolemy/processFileBase.py +79 -18
  243. snappy/ptolemy/processFileDispatch.py +13 -14
  244. snappy/ptolemy/processMagmaFile.py +44 -39
  245. snappy/ptolemy/processRurFile.py +18 -11
  246. snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +20 -17
  247. snappy/ptolemy/ptolemyObstructionClass.py +13 -17
  248. snappy/ptolemy/ptolemyVariety.py +190 -121
  249. snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +20 -19
  250. snappy/ptolemy/reginaWrapper.py +25 -29
  251. snappy/ptolemy/rur.py +6 -14
  252. snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +27 -22
  253. snappy/ptolemy/test.py +247 -188
  254. snappy/ptolemy/utilities.py +41 -43
  255. snappy/raytracing/__init__.py +64 -0
  256. snappy/raytracing/additional_horospheres.py +64 -0
  257. snappy/raytracing/additional_len_spec_choices.py +63 -0
  258. snappy/raytracing/cohomology_fractal.py +10 -6
  259. snappy/raytracing/eyeball.py +123 -0
  260. snappy/raytracing/finite_raytracing_data.py +48 -38
  261. snappy/raytracing/finite_viewer.py +218 -210
  262. snappy/raytracing/geodesic_tube_info.py +174 -0
  263. snappy/raytracing/geodesics.py +246 -0
  264. snappy/raytracing/geodesics_window.py +258 -0
  265. snappy/raytracing/gui_utilities.py +152 -40
  266. snappy/raytracing/hyperboloid_navigation.py +102 -52
  267. snappy/raytracing/hyperboloid_utilities.py +114 -261
  268. snappy/raytracing/ideal_raytracing_data.py +256 -179
  269. snappy/raytracing/inside_viewer.py +522 -253
  270. snappy/raytracing/pack.py +22 -0
  271. snappy/raytracing/raytracing_data.py +46 -34
  272. snappy/raytracing/raytracing_view.py +190 -109
  273. snappy/raytracing/shaders/Eye.png +0 -0
  274. snappy/raytracing/shaders/NonGeometric.png +0 -0
  275. snappy/raytracing/shaders/__init__.py +60 -4
  276. snappy/raytracing/shaders/fragment.glsl +575 -148
  277. snappy/raytracing/test.py +29 -0
  278. snappy/raytracing/tooltip.py +146 -0
  279. snappy/raytracing/upper_halfspace_utilities.py +98 -0
  280. snappy/raytracing/view_scale_controller.py +98 -0
  281. snappy/raytracing/zoom_slider/__init__.py +32 -29
  282. snappy/raytracing/zoom_slider/test.py +2 -0
  283. snappy/sage_helper.py +69 -123
  284. snappy/{preferences.py → settings.py} +167 -145
  285. snappy/shell.py +4 -0
  286. snappy/snap/__init__.py +12 -8
  287. snappy/snap/character_varieties.py +24 -18
  288. snappy/snap/find_field.py +35 -34
  289. snappy/snap/fundamental_polyhedron.py +99 -85
  290. snappy/snap/generators.py +6 -8
  291. snappy/snap/interval_reps.py +18 -6
  292. snappy/snap/kernel_structures.py +8 -3
  293. snappy/snap/mcomplex_base.py +1 -2
  294. snappy/snap/nsagetools.py +107 -53
  295. snappy/snap/peripheral/__init__.py +1 -1
  296. snappy/snap/peripheral/dual_cellulation.py +15 -7
  297. snappy/snap/peripheral/link.py +20 -16
  298. snappy/snap/peripheral/peripheral.py +22 -14
  299. snappy/snap/peripheral/surface.py +47 -50
  300. snappy/snap/peripheral/test.py +8 -8
  301. snappy/snap/polished_reps.py +65 -40
  302. snappy/snap/shapes.py +41 -22
  303. snappy/snap/slice_obs_HKL.py +64 -25
  304. snappy/snap/t3mlite/arrow.py +88 -51
  305. snappy/snap/t3mlite/corner.py +5 -6
  306. snappy/snap/t3mlite/edge.py +32 -21
  307. snappy/snap/t3mlite/face.py +7 -9
  308. snappy/snap/t3mlite/files.py +31 -23
  309. snappy/snap/t3mlite/homology.py +14 -10
  310. snappy/snap/t3mlite/linalg.py +158 -56
  311. snappy/snap/t3mlite/mcomplex.py +739 -291
  312. snappy/snap/t3mlite/perm4.py +236 -84
  313. snappy/snap/t3mlite/setup.py +9 -10
  314. snappy/snap/t3mlite/simplex.py +65 -48
  315. snappy/snap/t3mlite/spun.py +42 -30
  316. snappy/snap/t3mlite/surface.py +45 -45
  317. snappy/snap/t3mlite/test.py +3 -0
  318. snappy/snap/t3mlite/test_vs_regina.py +17 -13
  319. snappy/snap/t3mlite/tetrahedron.py +25 -24
  320. snappy/snap/t3mlite/vertex.py +8 -13
  321. snappy/snap/test.py +45 -52
  322. snappy/snap/utilities.py +66 -65
  323. snappy/test.py +155 -158
  324. snappy/test_cases.py +263 -0
  325. snappy/testing.py +131 -0
  326. snappy/tiling/__init__.py +2 -0
  327. snappy/tiling/canonical_key_dict.py +59 -0
  328. snappy/tiling/dict_based_set.py +79 -0
  329. snappy/tiling/floor.py +49 -0
  330. snappy/tiling/hyperboloid_dict.py +54 -0
  331. snappy/tiling/iter_utils.py +78 -0
  332. snappy/tiling/lifted_tetrahedron.py +22 -0
  333. snappy/tiling/lifted_tetrahedron_set.py +54 -0
  334. snappy/tiling/real_hash_dict.py +164 -0
  335. snappy/tiling/test.py +23 -0
  336. snappy/tiling/tile.py +215 -0
  337. snappy/tiling/triangle.py +33 -0
  338. snappy/tkterminal.py +313 -203
  339. snappy/twister/main.py +1 -8
  340. snappy/twister/twister_core.cpython-38-darwin.so +0 -0
  341. snappy/upper_halfspace/__init__.py +146 -0
  342. snappy/upper_halfspace/ideal_point.py +26 -0
  343. snappy/verify/__init__.py +4 -8
  344. snappy/verify/{verifyCanonical.py → canonical.py} +114 -97
  345. snappy/verify/complex_volume/__init__.py +3 -2
  346. snappy/verify/complex_volume/adjust_torsion.py +13 -11
  347. snappy/verify/complex_volume/closed.py +29 -24
  348. snappy/verify/complex_volume/compute_ptolemys.py +8 -6
  349. snappy/verify/complex_volume/cusped.py +10 -9
  350. snappy/verify/complex_volume/extended_bloch.py +14 -12
  351. snappy/verify/{cuspTranslations.py → cusp_translations.py} +15 -14
  352. snappy/verify/edge_equations.py +80 -0
  353. snappy/verify/exceptions.py +23 -56
  354. snappy/verify/{verifyHyperbolicity.py → hyperbolicity.py} +19 -15
  355. snappy/verify/interval_newton_shapes_engine.py +51 -211
  356. snappy/verify/interval_tree.py +27 -25
  357. snappy/verify/krawczyk_shapes_engine.py +47 -50
  358. snappy/verify/maximal_cusp_area_matrix/__init__.py +17 -86
  359. snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +58 -48
  360. snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +53 -57
  361. snappy/verify/{realAlgebra.py → real_algebra.py} +26 -20
  362. snappy/verify/shapes.py +10 -7
  363. snappy/verify/short_slopes.py +41 -42
  364. snappy/verify/{squareExtensions.py → square_extensions.py} +96 -92
  365. snappy/verify/test.py +59 -57
  366. snappy/verify/upper_halfspace/extended_matrix.py +5 -5
  367. snappy/verify/upper_halfspace/finite_point.py +44 -31
  368. snappy/verify/upper_halfspace/ideal_point.py +69 -57
  369. snappy/verify/volume.py +15 -12
  370. snappy/version.py +2 -3
  371. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/METADATA +14 -12
  372. snappy-3.2.dist-info/RECORD +503 -0
  373. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/WHEEL +1 -1
  374. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/entry_points.txt +0 -1
  375. {snappy-3.0.3.dist-info → snappy-3.2.dist-info}/top_level.txt +10 -1
  376. snappy/doc/_sources/verify_canon.rst.txt +0 -90
  377. snappy/doc/_static/classic.css +0 -266
  378. snappy/doc/_static/jquery-3.5.1.js +0 -10872
  379. snappy/doc/_static/sidebar.js +0 -159
  380. snappy/doc/_static/underscore-1.13.1.js +0 -2042
  381. snappy/doc/_static/underscore.js +0 -6
  382. snappy/doc/verify_canon.html +0 -283
  383. snappy/ppm_to_png.py +0 -243
  384. snappy/togl/__init__.py +0 -3
  385. snappy/togl/darwin-tk8.6/Togl2.1/LICENSE +0 -28
  386. snappy/togl/darwin-tk8.6/Togl2.1/libTogl2.1.dylib +0 -0
  387. snappy/togl/darwin-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  388. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  389. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/libTogl2.1.so +0 -0
  390. snappy/togl/linux2-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -5
  391. snappy/togl/win32VC-tk8.6/Togl2.1/LICENSE +0 -28
  392. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.dll +0 -0
  393. snappy/togl/win32VC-tk8.6/Togl2.1/Togl21.lib +0 -0
  394. snappy/togl/win32VC-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  395. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/LICENSE +0 -28
  396. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.dll +0 -0
  397. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/Togl21.lib +0 -0
  398. snappy/togl/win32VC-x86_64-tk8.6/Togl2.1/pkgIndex.tcl +0 -6
  399. snappy/verify/cuspCrossSection.py +0 -1413
  400. snappy/verify/mathHelpers.py +0 -64
  401. snappy-3.0.3.dist-info/RECORD +0 -360
@@ -0,0 +1,620 @@
1
+ from .cusps import CuspPostDrillInfo
2
+ from .tracing import compute_plane_intersection_param, Endpoint, GeodesicPiece
3
+ from .epsilons import compute_epsilon
4
+ from . import constants
5
+ from . import exceptions
6
+
7
+ from ..geometric_structure import add_r13_planes_to_tetrahedron
8
+ from ..snap.t3mlite import simplex, Perm4, Tetrahedron, Corner # type: ignore
9
+ from ..matrix import make_identity_matrix # type: ignore
10
+ from ..exceptions import InsufficientPrecisionError # type: ignore
11
+
12
+ from typing import Sequence, Optional, List
13
+
14
+ __all__ = ['one_four_move', 'two_three_move']
15
+
16
+ def one_four_move(given_pieces : Sequence[GeodesicPiece],
17
+ verified : bool) -> Sequence[GeodesicPiece]:
18
+ """
19
+ Performs a 1-4 move.
20
+
21
+ Given pieces are supposed to be either two pieces
22
+ F-T-F (see subdivide.py for notation) or just one piece F-F.
23
+
24
+ For F-T-F, the new point for the 1-4 move will be the one given
25
+ for T. For F-F, the 1-4 move will pick a point on the line segment
26
+ (not picking exactly the middle to avoid coincidences).
27
+ """
28
+
29
+ tet : Tetrahedron = given_pieces[0].tet
30
+ RF = tet.O13_matrices[simplex.F0].base_ring()
31
+
32
+ if not given_pieces[0].endpoints[0].subsimplex in simplex.TwoSubsimplices:
33
+ raise Exception("Expected given geodesic piece to start "
34
+ "on a face for one-four move.")
35
+ if not given_pieces[-1].endpoints[1].subsimplex in simplex.TwoSubsimplices:
36
+ raise Exception("Expected given geodesic piece to end "
37
+ "on a face for one-four move.")
38
+
39
+ n = len(given_pieces)
40
+
41
+ if n == 1:
42
+ bias = RF(constants.piece_midpoint_bias)
43
+ new_point = (
44
+ given_pieces[0].endpoints[0].r13_point +
45
+ bias * given_pieces[0].endpoints[1].r13_point)
46
+ elif n == 2:
47
+ if not given_pieces[0].endpoints[1].subsimplex == simplex.T:
48
+ raise Exception("Expected middle point to be in the tetrahedron "
49
+ "when given two pieces to one-four move.")
50
+ if not given_pieces[1].endpoints[0].subsimplex == simplex.T:
51
+ raise Exception("Expected middle point to be in the tetrahedron "
52
+ "when given two pieces to one-four move.")
53
+
54
+ if not given_pieces[0].tet is given_pieces[1].tet:
55
+ raise Exception("Expected pieces to be in the same tetrahedron "
56
+ "when given two pieces to one-four move.")
57
+
58
+ new_point = given_pieces[0].endpoints[1].r13_point
59
+ else:
60
+ raise Exception("Bad 1-4 move")
61
+
62
+ # The new tetrahedra.
63
+ # new_tets[f] shares face f with the old tetrahedron.
64
+ # That is vertex v of the new tetrahedron corresponds to
65
+ # vertex v of the old tetrahedron if v is on the face f.
66
+ # Otherwise, the vertex v of the new tetrahedron corresponds
67
+ # to the new vertex in the center.
68
+
69
+ new_tets : dict[int, Tetrahedron] = {
70
+ f : Tetrahedron() for f in simplex.TwoSubsimplices }
71
+
72
+ neighbors : dict[int, Tetrahedron] = dict(tet.Neighbor.items())
73
+ gluings : dict[int, Perm4] = dict(tet.Gluing.items())
74
+
75
+ id_matrix = make_identity_matrix(ring=RF, n=4)
76
+
77
+ for f0, new_tet0 in new_tets.items():
78
+ new_tet0.geodesic_pieces = []
79
+ v0 = simplex.comp(f0)
80
+ new_tet0.R13_vertices = { v0 : new_point }
81
+ new_tet0.post_drill_infos = {
82
+ v0 : CuspPostDrillInfo(index=given_pieces[0].index) }
83
+ new_tet0.O13_matrices = {}
84
+ new_tet0.PeripheralCurves = [
85
+ [ { v : { face : 0 for face in simplex.TwoSubsimplices }
86
+ for v in simplex.ZeroSubsimplices }
87
+ for sheet in range(2) ]
88
+ for ml in range(2) ]
89
+
90
+ for f1, new_tet1 in new_tets.items():
91
+ if f0 != f1:
92
+ new_tet0.attach(f1, new_tet1, _swap_perms[f0, f1])
93
+ v1 = simplex.comp(f1)
94
+ new_tet0.R13_vertices[v1] = tet.R13_vertices[v1]
95
+ new_tet0.post_drill_infos[v1] = tet.post_drill_infos[v1]
96
+ new_tet0.O13_matrices[f1] = id_matrix
97
+
98
+ neighbor : Tetrahedron = neighbors[f0]
99
+ gluing : Perm4 = gluings[f0]
100
+ if neighbor is tet:
101
+ other_tet = new_tets[gluing.image(f0)]
102
+ else:
103
+ other_tet = neighbor
104
+ new_tet0.attach(f0, other_tet, gluing.tuple())
105
+
106
+ new_tet0.O13_matrices[f0] = tet.O13_matrices[f0]
107
+
108
+ add_r13_planes_to_tetrahedron(new_tet0)
109
+
110
+ for ml in range(2):
111
+ for sheet in range(2):
112
+ for v, faces in simplex.FacesAroundVertexCounterclockwise.items():
113
+ for face in faces:
114
+ new_tets[face].PeripheralCurves[ml][sheet][v][face] = (
115
+ tet.PeripheralCurves[ml][sheet][v][face])
116
+ f0, f1, f2 = faces
117
+ new_tets[f0].PeripheralCurves[ml][sheet][v][f1] = (
118
+ -tet.PeripheralCurves[ml][sheet][v][f0])
119
+ new_tets[f1].PeripheralCurves[ml][sheet][v][f0] = (
120
+ tet.PeripheralCurves[ml][sheet][v][f0])
121
+ new_tets[f1].PeripheralCurves[ml][sheet][v][f2] = (
122
+ tet.PeripheralCurves[ml][sheet][v][f2])
123
+ new_tets[f2].PeripheralCurves[ml][sheet][v][f1] = (
124
+ -tet.PeripheralCurves[ml][sheet][v][f2])
125
+
126
+ # Transfer or re-trace the other pieces of the geodesic going through
127
+ # the old tetrahedron in the new tetrahedra.
128
+ for old_piece in tet.geodesic_pieces:
129
+ if old_piece in given_pieces:
130
+ continue
131
+
132
+ start_subsimplex : int = old_piece.endpoints[0].subsimplex
133
+ end_subsimplex : int = old_piece.endpoints[1].subsimplex
134
+
135
+ dimension_start_subsimplex = simplex.dimension(start_subsimplex)
136
+ dimension_end_subsimplex = simplex.dimension(end_subsimplex)
137
+
138
+ if dimension_start_subsimplex == 0 and dimension_end_subsimplex == 0:
139
+ # Both endpoints are vertices, no re-tracing necessary.
140
+ total_subsimplex = start_subsimplex | end_subsimplex
141
+ for new_face, new_tet in new_tets.items():
142
+ if simplex.is_subset(total_subsimplex, new_face):
143
+ GeodesicPiece.replace_by(
144
+ old_piece, old_piece,
145
+ [ GeodesicPiece.create_and_attach(
146
+ old_piece.index,
147
+ new_tet,
148
+ old_piece.endpoints) ])
149
+ break
150
+ else:
151
+ raise Exception("Unhandled edge case")
152
+ else:
153
+ # Re-trace.
154
+ r13_endpoints = [ e.r13_point for e in old_piece.endpoints ]
155
+
156
+ GeodesicPiece.replace_by(
157
+ old_piece, old_piece,
158
+ _retrace_geodesic_piece(
159
+ index=old_piece.index,
160
+ r13_points=r13_endpoints,
161
+ start_corners=[ Corner(new_tets[f], start_subsimplex)
162
+ for f in simplex.TwoSubsimplices
163
+ if simplex.is_subset(start_subsimplex, f) ],
164
+ end_corners=[ Corner(new_tets[f], end_subsimplex)
165
+ for f in simplex.TwoSubsimplices
166
+ if simplex.is_subset(end_subsimplex, f) ],
167
+ verified=verified))
168
+
169
+ # Turn given pieces into F-V-F
170
+ start_point : Endpoint = given_pieces[0].endpoints[0]
171
+ end_point : Endpoint = given_pieces[-1].endpoints[1]
172
+ new_pieces : Sequence[GeodesicPiece] = [
173
+ GeodesicPiece.create_face_to_vertex_and_attach(
174
+ given_pieces[0].index,
175
+ new_tets[start_point.subsimplex],
176
+ start_point,
177
+ direction=+1),
178
+ GeodesicPiece.create_face_to_vertex_and_attach(
179
+ given_pieces[0].index,
180
+ new_tets[end_point.subsimplex],
181
+ end_point,
182
+ direction=-1) ]
183
+
184
+ GeodesicPiece.replace_by(
185
+ given_pieces[0], given_pieces[-1], new_pieces)
186
+
187
+ return new_pieces
188
+
189
+ def two_three_move(given_pieces : Sequence[GeodesicPiece],
190
+ verified : bool) -> Sequence[GeodesicPiece]:
191
+ """
192
+ Expects two given pieces V-F-V which form one straight line
193
+ segment from V to V.
194
+
195
+ The 2-3 move is performed on the two tetrahedra adjacent to
196
+ that face.
197
+ """
198
+
199
+ # We imagine the two old tetrahedra such that the shared face
200
+ # is horizontal. We list them in the order where the top one
201
+ # is first and has index 0.
202
+
203
+ old_tets = [ old_piece.tet for old_piece in given_pieces ]
204
+ old_tips = [ given_pieces[i].endpoints[i].subsimplex
205
+ for i in range(2) ]
206
+ # For each old tetrahedron, its face that it shared with the other
207
+ # tetrahedron.
208
+ old_shared_faces = [ simplex.comp(old_tip)
209
+ for old_tip in old_tips ]
210
+
211
+ RF = old_tets[0].O13_matrices[simplex.F0].base_ring()
212
+ id_matrix = make_identity_matrix(ring=RF, n=4)
213
+
214
+ # Embeddings to map both tetrahedra into the same coordinate
215
+ # system
216
+ O13_embeddings = [ old_tets[0].O13_matrices[old_shared_faces[0]],
217
+ id_matrix ]
218
+ O13_inverse_embeddings = [ old_tets[1].O13_matrices[old_shared_faces[1]],
219
+ id_matrix ]
220
+
221
+ tip_points = [
222
+ O13_embeddings[i] * old_tets[i].R13_vertices[old_tips[i]]
223
+ for i in range(2) ]
224
+
225
+ # Find permutation such that we can label the top vertex of
226
+ # the top tetrahedron by 0.
227
+ for perm in Perm4.A4():
228
+ if perm.image(simplex.V0) == old_tips[0]:
229
+ break
230
+ gluing = old_tets[0].Gluing[old_shared_faces[0]]
231
+
232
+ new_to_old_tets = [ [ p, gluing * p * Perm4((1,0,2,3)) ]
233
+ for p in [ perm,
234
+ perm * Perm4((0,2,3,1)),
235
+ perm * Perm4((0,3,1,2)) ] ]
236
+
237
+ # The new tetrahedra have vertices as follows:
238
+ # Vertex 0 always corresponds to the top vertex of the
239
+ # top tetrahedron.
240
+ # Vertex 1 always corresponds to the top vertex of the
241
+ # bottom tetrahedron
242
+ # Vertex 3 is glued to vertex 2 of the next tetrahedron.
243
+ #
244
+ # Note that face 0 of a new tetrahedron is shared with
245
+ # some face of the old top tetrahedron (index=1).
246
+ # Similarly for face 1 and the bottom tetrahedron (index=0).
247
+ #
248
+ new_tets = [ Tetrahedron() for i in range(3) ]
249
+
250
+ for i, new_tet in enumerate(new_tets):
251
+ new_tet.geodesic_pieces = []
252
+ new_tet.O13_matrices = {
253
+ simplex.F2 : id_matrix,
254
+ simplex.F3 : id_matrix
255
+ }
256
+ new_tet.PeripheralCurves = [
257
+ [ { v : { face : 0 for face in simplex.TwoSubsimplices }
258
+ for v in simplex.ZeroSubsimplices }
259
+ for sheet in range(2) ]
260
+ for ml in range(2) ]
261
+
262
+ for j, old_tet in enumerate(old_tets):
263
+ new_face = simplex.TwoSubsimplices[1-j]
264
+ old_face = new_to_old_tets[i][j].image(new_face)
265
+ neighbor = old_tet.Neighbor[old_face]
266
+ new_tet.attach(
267
+ new_face,
268
+ neighbor,
269
+ old_tet.Gluing[old_face] * new_to_old_tets[i][j])
270
+ new_tet.O13_matrices[new_face] = (
271
+ old_tet.O13_matrices[old_face] * O13_inverse_embeddings[j])
272
+
273
+ neighbor_face = new_tet.Gluing[new_face].image(new_face)
274
+ neighbor.O13_matrices[neighbor_face] = (
275
+ O13_embeddings[j] * neighbor.O13_matrices[neighbor_face])
276
+
277
+ for ml in range(2):
278
+ for sheet in range(2):
279
+ for v in [ simplex.V2, simplex.V3 ]:
280
+ old_v = new_to_old_tets[i][j].image(v)
281
+ new_tet.PeripheralCurves[ml][sheet][v][new_face] = (
282
+ old_tet.PeripheralCurves[ml][sheet][old_v][old_face])
283
+
284
+ for ml in range(2):
285
+ for sheet in range(2):
286
+ for v, f in [ (simplex.V2, simplex.F3), (simplex.V3, simplex.F2) ]:
287
+ p = new_tet.PeripheralCurves[ml][sheet][v]
288
+ p[f] = - (p[simplex.F0] + p[simplex.F1])
289
+
290
+ new_tet.attach(
291
+ simplex.F2,
292
+ new_tets[(i+1) % 3],
293
+ (0,1,3,2))
294
+
295
+ new_tet.R13_vertices = {
296
+ simplex.V0 : tip_points[0],
297
+ simplex.V1 : tip_points[1],
298
+ simplex.V2 : old_tets[1].R13_vertices[new_to_old_tets[i][1].image(simplex.V2)],
299
+ simplex.V3 : old_tets[1].R13_vertices[new_to_old_tets[i][1].image(simplex.V3)],
300
+ }
301
+
302
+ new_tet.post_drill_infos = {
303
+ simplex.V0 : old_tets[0].post_drill_infos[old_tips[0]],
304
+ simplex.V1 : old_tets[1].post_drill_infos[old_tips[1]],
305
+ simplex.V2 : old_tets[1].post_drill_infos[new_to_old_tets[i][1].image(simplex.V2)],
306
+ simplex.V3 : old_tets[1].post_drill_infos[new_to_old_tets[i][1].image(simplex.V3)],
307
+ }
308
+
309
+ add_r13_planes_to_tetrahedron(new_tet)
310
+
311
+ old_to_new_tets = [ [ ~new_to_old_tets[j][i] for j in range(3) ]
312
+ for i in range(2) ]
313
+
314
+ # Transfer or re-trace the other pieces of the geodesic going through
315
+ # the old tetrahedron in the new tetrahedra.
316
+ # Consider one old tetrahedron at a time.
317
+ for j, old_tet in enumerate(old_tets):
318
+ for old_piece in old_tet.geodesic_pieces:
319
+
320
+ if old_piece in given_pieces:
321
+ continue
322
+
323
+ start_point = old_piece.endpoints[0]
324
+ start_subsimplex = start_point.subsimplex
325
+ # Index of old tet where piece is starting
326
+ start_j = j
327
+
328
+ # A geodesic piece crossing the face shared between the bottom and
329
+ # top tetrahedron was originally two pieces. Of these two pieces,
330
+ # discard the one after crossing the shared face.
331
+ if start_subsimplex == old_shared_faces[j]:
332
+ continue
333
+
334
+ end_point = old_piece.endpoints[1]
335
+ end_subsimplex = end_point.subsimplex
336
+ # Index of old tet where piece is ending
337
+ end_j = j
338
+
339
+ old_pieces = [ old_piece ]
340
+ # If a geodesic piece ends at the shared face, merge it
341
+ # with the next piece.
342
+ if end_subsimplex == old_shared_faces[j]:
343
+ old_pieces.append(old_piece.next_)
344
+ end_point = old_piece.next_.endpoints[1]
345
+ end_subsimplex = end_point.subsimplex
346
+ end_j = 1 - j
347
+
348
+ dimension_start_subsimplex = simplex.dimension(start_subsimplex)
349
+ dimension_end_subsimplex = simplex.dimension(end_subsimplex)
350
+
351
+ # Face of new tetrahedron that is shared with old tetrahedron.
352
+ new_start_face = simplex.TwoSubsimplices[1 - start_j]
353
+ new_end_face = simplex.TwoSubsimplices[1 - end_j]
354
+
355
+ if dimension_start_subsimplex == 0 and dimension_end_subsimplex == 0:
356
+ # Vertex to vertex piece. We can just transfer.
357
+ for i, new_tet in enumerate(new_tets):
358
+ # We need to find the right new tetrahedron such that the
359
+ # geodesic piece is an edge of the face shared with the old
360
+ # tetrahedron.
361
+ new_start_subsimplex = old_to_new_tets[j][i].image(start_subsimplex)
362
+ new_end_subsimplex = old_to_new_tets[j][i].image(end_subsimplex)
363
+ new_subsimplex = new_start_subsimplex | new_end_subsimplex
364
+
365
+ if simplex.is_subset(new_subsimplex, new_start_face):
366
+ GeodesicPiece.replace_by(
367
+ old_pieces[0], old_pieces[-1],
368
+ [
369
+ GeodesicPiece.create_and_attach(
370
+ old_piece.index,
371
+ new_tet,
372
+ [ Endpoint(new_tet.R13_vertices[v], v)
373
+ for v in [ new_start_subsimplex, new_end_subsimplex ] ])])
374
+ break
375
+ else:
376
+ raise Exception("Unhandled edge case.")
377
+ else:
378
+ # We need to re-trace.
379
+ r13_endpoints = [
380
+ O13_embeddings[start_j] * start_point.r13_point,
381
+ O13_embeddings[end_j] * end_point.r13_point
382
+ ]
383
+
384
+ new_start_subsimplices = [
385
+ old_to_new_tets[start_j][i].image(start_subsimplex)
386
+ for i in range(3) ]
387
+ start_corners = [
388
+ Corner(new_tets[i], new_start_subsimplices[i])
389
+ for i in range(3)
390
+ if simplex.is_subset(new_start_subsimplices[i], new_start_face) ]
391
+ new_end_subsimplices = [
392
+ old_to_new_tets[end_j][i].image(end_subsimplex)
393
+ for i in range(3) ]
394
+ end_corners = [
395
+ Corner(new_tets[i], new_end_subsimplices[i])
396
+ for i in range(3)
397
+ if simplex.is_subset(new_end_subsimplices[i], new_end_face) ]
398
+
399
+ GeodesicPiece.replace_by(
400
+ old_pieces[0], old_pieces[-1],
401
+ _retrace_geodesic_piece(
402
+ index=old_piece.index,
403
+ r13_points=r13_endpoints,
404
+ start_corners=start_corners,
405
+ end_corners=end_corners,
406
+ verified=verified))
407
+
408
+ # Given pieces are converted to one V-V piece.
409
+ new_piece = GeodesicPiece.create_and_attach(
410
+ given_pieces[0].index,
411
+ new_tets[0],
412
+ [ Endpoint(tip_points[0], simplex.V0),
413
+ Endpoint(tip_points[1], simplex.V1) ])
414
+ GeodesicPiece.replace_by(
415
+ given_pieces[0], given_pieces[1],
416
+ [new_piece])
417
+
418
+ return new_piece
419
+
420
+ def _swap_perm(i, j):
421
+ result = [0, 1, 2, 3]
422
+ result[i] = j
423
+ result[j] = i
424
+ return result
425
+
426
+ _swap_perms = { (f0, f1) : _swap_perm(i, j)
427
+ for i, f0 in enumerate(simplex.TwoSubsimplices)
428
+ for j, f1 in enumerate(simplex.TwoSubsimplices) }
429
+
430
+ # Re-trace a line segment between two points in R^{1,3} in the new
431
+ # tetrahedra (which are assumed to be all in the same coordinate system).
432
+ #
433
+ # We are given the combinatorial information about the start and end points
434
+ # of the line segment through Corner's which are pairs of a tetrahedron and
435
+ # subsimplex.
436
+ #
437
+ # If such a start or end point is on a face, we give retrace exactly one
438
+ # corner encoding the face of the respective tetrahedron.
439
+ #
440
+ # If such a point is inside one of the new tetrahedra (we do not know yet
441
+ # which), we given an empty list of Corner's.
442
+ #
443
+ # If such a point is a vertex, we give all pairs of a new tetrahedron
444
+ # and one of its vertices that correspond to this vertex.
445
+ #
446
+ # index identifies to which of the geodesics we want to drill the retraced
447
+ # pieces belong. It is the index of the cusp that the geodesic will become
448
+ # in the drilled manifold.
449
+ #
450
+ def _retrace_geodesic_piece(
451
+ index : int,
452
+ r13_points,
453
+ start_corners : Sequence[Corner],
454
+ end_corners : Sequence[Corner],
455
+ verified : bool) -> Sequence[GeodesicPiece]:
456
+
457
+ if len(start_corners) == 1:
458
+ # If we have a unique start corner (which is supposed
459
+ # to be a face of a tetrahedron), we can just start
460
+ # tracing from that face.
461
+ trace_direction = +1
462
+ else:
463
+ # Otherwise, we need to trace the other way.
464
+ # The end corner was supposed to be a face of a tetrahedron
465
+ # in this case.
466
+ trace_direction = -1
467
+ start_corners, end_corners = end_corners, start_corners
468
+ r13_points = r13_points[::-1]
469
+
470
+ if len(start_corners) != 1:
471
+ raise Exception("No unique start corner")
472
+
473
+ # Tet and face to start re-tracing
474
+ tet = start_corners[0].Tetrahedron
475
+ face = start_corners[0].Subsimplex
476
+
477
+ if face not in simplex.TwoSubsimplices:
478
+ raise Exception("Tracing not starting on a face")
479
+
480
+ # Get dimension of subsimplex where line segment
481
+ # we are re-tracing ends.
482
+ dimension_end_subsimplex = 3
483
+ if len(end_corners) > 0:
484
+ dimension_end_subsimplex = simplex.dimension(
485
+ end_corners[0].Subsimplex)
486
+
487
+ start_point, end_point = r13_points
488
+
489
+ RF = start_point[0].parent()
490
+ if verified:
491
+ epsilon = 0
492
+ else:
493
+ epsilon = compute_epsilon(RF)
494
+
495
+ # Result
496
+ pieces : List[GeodesicPiece] = []
497
+
498
+ # Parametrizes ray. That is, we are start_point + param * direction.
499
+ param = RF(0)
500
+ direction = end_point - start_point
501
+
502
+ # 1-4 and 2-3 move never breaks up one line segment into more
503
+ # than 4 pieces.
504
+ for i in range(4):
505
+ hit_end : bool = False
506
+ # Record the face and param through which the ray is leaving
507
+ # the tet - that is which face the ray is hitting next.
508
+ hit_subsimplex : Optional[int] = None
509
+ hit_param = None
510
+
511
+ if dimension_end_subsimplex == 0:
512
+ # Check if we just entered a tetrahedron adjacent to the
513
+ # vertex where the line segments stops.
514
+ for end_corner in end_corners:
515
+ if tet == end_corner.Tetrahedron:
516
+ # If that is true, we have finished re-tracing
517
+ # and just need to emit the final F-V piece below.
518
+ # Do some sanity checks first though.
519
+ hit_subsimplex = simplex.comp(face)
520
+ if hit_subsimplex != end_corner.Subsimplex:
521
+ raise Exception("Implementation error: "
522
+ "ray entered tetrahedron through "
523
+ "unexpected face.")
524
+ hit_end = True
525
+
526
+ if not hit_end:
527
+ # Above condition not met, do actual ray-tracing.
528
+ if dimension_end_subsimplex == 3:
529
+ # The line-segment to be re-traced ends in the interior
530
+ # of a simplex. We set hit_param to 1 so that any face
531
+ # the ray hits after reaching the end of the line
532
+ # segment are ignored.
533
+ hit_subsimplex = simplex.T
534
+ hit_param = RF(1)
535
+
536
+ # Now intersect the ray with each face we did not enter through.
537
+ for candidate_face, plane in tet.R13_unnormalised_planes.items():
538
+ # Skip the face through which the ray just entered the tet
539
+ if candidate_face == face:
540
+ continue
541
+ # Compute the param at which the ray intersects this face
542
+ candidate_param = compute_plane_intersection_param(
543
+ plane, start_point, direction, verified)
544
+
545
+ # If the ray crossed this face before it crossed the
546
+ # entry face, ignore. Can happen when a dihedral angle is obtuse.
547
+ if candidate_param < param - epsilon:
548
+ continue
549
+ if not candidate_param > param + epsilon:
550
+ raise InsufficientPrecisionError(
551
+ "When re-tracing the geodesic, the intersection with the "
552
+ "next tetrahedron face was too close to the previous "
553
+ "to tell them apart. Increasing the precision will "
554
+ "probably avoid this problem.")
555
+
556
+ # This face is the (potential) exit face if the ray crossed
557
+ # it before it crossed the other faces (encountered so far).
558
+ if hit_param is None:
559
+ # No other face encountered so far
560
+ hit_param = candidate_param
561
+ hit_subsimplex = candidate_face
562
+ else:
563
+ # Check this face crossed before other faces
564
+ if candidate_param + epsilon < hit_param:
565
+ hit_param = candidate_param
566
+ hit_subsimplex = candidate_face
567
+ elif not candidate_param > hit_param + epsilon:
568
+ # If there is any ambiguity whether this face was
569
+ # crossed before the other face, fail!
570
+ # Most likely, this is because the ray is close to
571
+ # or crossing an edge of the triangulation.
572
+ raise exceptions.RetracingRayHittingOneSkeletonError()
573
+
574
+ if hit_param is None or hit_subsimplex is None:
575
+ raise InsufficientPrecisionError(
576
+ "Could not find the next intersection of the geodesic with a "
577
+ "tetrahedron face. Increasing the precision should solve this "
578
+ "problem.")
579
+
580
+ if dimension_end_subsimplex == 3:
581
+ # If we hit not face before the line segment ended, we are done
582
+ # Emit final F-T segment below.
583
+ if hit_subsimplex == simplex.T:
584
+ hit_end = True
585
+ else:
586
+ if hit_subsimplex == simplex.T:
587
+ raise Exception("Implementation error. Got interior of "
588
+ "simplex when expected face.")
589
+ # Did we hit the face where the line segment is ending at?
590
+ hit_end = (
591
+ tet == end_corners[0].Tetrahedron and
592
+ hit_subsimplex == end_corners[0].Subsimplex)
593
+
594
+ if hit_end:
595
+ # Use end point of line segment if we hit the end.
596
+ point = end_point
597
+ else:
598
+ # Advance ray.
599
+ point = start_point + hit_param * direction
600
+
601
+ endpoints = [ Endpoint(start_point + param * direction, face),
602
+ Endpoint(point, hit_subsimplex) ][::trace_direction]
603
+
604
+ pieces.append(
605
+ GeodesicPiece.create_and_attach(index, tet, endpoints))
606
+
607
+ if hit_end:
608
+ break
609
+
610
+ # Teleport to the next tetrahedron.
611
+ face = tet.Gluing[hit_subsimplex].image(hit_subsimplex)
612
+ tet = tet.Neighbor[hit_subsimplex]
613
+ param = hit_param
614
+ else:
615
+ raise Exception(
616
+ "Too many steps when re-tracing a geodesic piece. "
617
+ "This is either due to a lack of precision or an "
618
+ "implementation bug.")
619
+
620
+ return pieces[::trace_direction]