snappy 3.2__cp310-cp310-macosx_10_12_x86_64.whl
Sign up to get free protection for your applications and to get access to all the features.
- snappy/CyOpenGL.cpython-310-darwin.so +0 -0
- snappy/SnapPy.cpython-310-darwin.so +0 -0
- snappy/SnapPy.ico +0 -0
- snappy/SnapPy.png +0 -0
- snappy/SnapPyHP.cpython-310-darwin.so +0 -0
- snappy/__init__.py +760 -0
- snappy/app.py +605 -0
- snappy/app_menus.py +372 -0
- snappy/browser.py +998 -0
- snappy/cache.py +25 -0
- snappy/canonical.py +249 -0
- snappy/cusps/__init__.py +38 -0
- snappy/cusps/cusp_area_matrix.py +101 -0
- snappy/cusps/cusp_areas_from_matrix.py +173 -0
- snappy/cusps/maximal_cusp_area_matrix.py +136 -0
- snappy/cusps/test.py +21 -0
- snappy/cusps/trig_cusp_area_matrix.py +63 -0
- snappy/database.py +454 -0
- snappy/db_utilities.py +79 -0
- snappy/decorated_isosig.py +710 -0
- snappy/dev/__init__.py +0 -0
- snappy/dev/extended_ptolemy/__init__.py +8 -0
- snappy/dev/extended_ptolemy/closed.py +106 -0
- snappy/dev/extended_ptolemy/complexVolumesClosed.py +149 -0
- snappy/dev/extended_ptolemy/direct.py +42 -0
- snappy/dev/extended_ptolemy/extended.py +406 -0
- snappy/dev/extended_ptolemy/giac_helper.py +43 -0
- snappy/dev/extended_ptolemy/giac_rur.py +129 -0
- snappy/dev/extended_ptolemy/gluing.py +46 -0
- snappy/dev/extended_ptolemy/phc_wrapper.py +220 -0
- snappy/dev/extended_ptolemy/printMatrices.py +70 -0
- snappy/dev/vericlosed/__init__.py +1 -0
- snappy/dev/vericlosed/computeApproxHyperbolicStructureNew.py +159 -0
- snappy/dev/vericlosed/computeApproxHyperbolicStructureOrb.py +90 -0
- snappy/dev/vericlosed/computeVerifiedHyperbolicStructure.py +111 -0
- snappy/dev/vericlosed/gimbalLoopFinder.py +130 -0
- snappy/dev/vericlosed/hyperbolicStructure.py +313 -0
- snappy/dev/vericlosed/krawczykCertifiedEdgeLengthsEngine.py +165 -0
- snappy/dev/vericlosed/oneVertexTruncatedComplex.py +122 -0
- snappy/dev/vericlosed/orb/__init__.py +1 -0
- snappy/dev/vericlosed/orb/orb_solution_for_snappea_finite_triangulation_mac +0 -0
- snappy/dev/vericlosed/parseVertexGramMatrixFile.py +47 -0
- snappy/dev/vericlosed/polishApproxHyperbolicStructure.py +61 -0
- snappy/dev/vericlosed/test.py +54 -0
- snappy/dev/vericlosed/truncatedComplex.py +176 -0
- snappy/dev/vericlosed/verificationError.py +58 -0
- snappy/dev/vericlosed/verifyHyperbolicStructureEngine.py +177 -0
- snappy/doc/_images/SnapPy-196.png +0 -0
- snappy/doc/_images/geodesics.jpg +0 -0
- snappy/doc/_images/m004_paper_plane_on_systole.jpg +0 -0
- snappy/doc/_images/m125_paper_plane.jpg +0 -0
- snappy/doc/_images/mac.png +0 -0
- snappy/doc/_images/o9_00000_systole_paper_plane.jpg +0 -0
- snappy/doc/_images/o9_00000_systole_paper_plane_closer.jpg +0 -0
- snappy/doc/_images/plink-action.png +0 -0
- snappy/doc/_images/ubuntu.png +0 -0
- snappy/doc/_images/win7.png +0 -0
- snappy/doc/_sources/additional_classes.rst.txt +40 -0
- snappy/doc/_sources/bugs.rst.txt +14 -0
- snappy/doc/_sources/censuses.rst.txt +51 -0
- snappy/doc/_sources/credits.rst.txt +75 -0
- snappy/doc/_sources/development.rst.txt +259 -0
- snappy/doc/_sources/index.rst.txt +182 -0
- snappy/doc/_sources/installing.rst.txt +247 -0
- snappy/doc/_sources/manifold.rst.txt +6 -0
- snappy/doc/_sources/manifoldhp.rst.txt +46 -0
- snappy/doc/_sources/news.rst.txt +355 -0
- snappy/doc/_sources/other.rst.txt +25 -0
- snappy/doc/_sources/platonic_census.rst.txt +20 -0
- snappy/doc/_sources/plink.rst.txt +102 -0
- snappy/doc/_sources/ptolemy.rst.txt +66 -0
- snappy/doc/_sources/ptolemy_classes.rst.txt +42 -0
- snappy/doc/_sources/ptolemy_examples1.rst.txt +298 -0
- snappy/doc/_sources/ptolemy_examples2.rst.txt +363 -0
- snappy/doc/_sources/ptolemy_examples3.rst.txt +301 -0
- snappy/doc/_sources/ptolemy_examples4.rst.txt +61 -0
- snappy/doc/_sources/ptolemy_prelim.rst.txt +105 -0
- snappy/doc/_sources/screenshots.rst.txt +21 -0
- snappy/doc/_sources/snap.rst.txt +87 -0
- snappy/doc/_sources/snappy.rst.txt +28 -0
- snappy/doc/_sources/spherogram.rst.txt +103 -0
- snappy/doc/_sources/todo.rst.txt +47 -0
- snappy/doc/_sources/triangulation.rst.txt +11 -0
- snappy/doc/_sources/tutorial.rst.txt +49 -0
- snappy/doc/_sources/verify.rst.txt +210 -0
- snappy/doc/_sources/verify_internals.rst.txt +79 -0
- snappy/doc/_static/SnapPy-horizontal-128.png +0 -0
- snappy/doc/_static/SnapPy.ico +0 -0
- snappy/doc/_static/_sphinx_javascript_frameworks_compat.js +123 -0
- snappy/doc/_static/basic.css +925 -0
- snappy/doc/_static/css/badge_only.css +1 -0
- snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- snappy/doc/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- snappy/doc/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- snappy/doc/_static/css/fonts/fontawesome-webfont.eot +0 -0
- snappy/doc/_static/css/fonts/fontawesome-webfont.svg +2671 -0
- snappy/doc/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- snappy/doc/_static/css/fonts/fontawesome-webfont.woff +0 -0
- snappy/doc/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- snappy/doc/_static/css/fonts/lato-bold-italic.woff +0 -0
- snappy/doc/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- snappy/doc/_static/css/fonts/lato-bold.woff +0 -0
- snappy/doc/_static/css/fonts/lato-bold.woff2 +0 -0
- snappy/doc/_static/css/fonts/lato-normal-italic.woff +0 -0
- snappy/doc/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- snappy/doc/_static/css/fonts/lato-normal.woff +0 -0
- snappy/doc/_static/css/fonts/lato-normal.woff2 +0 -0
- snappy/doc/_static/css/theme.css +4 -0
- snappy/doc/_static/doctools.js +156 -0
- snappy/doc/_static/documentation_options.js +13 -0
- snappy/doc/_static/file.png +0 -0
- snappy/doc/_static/fonts/Lato/lato-bold.eot +0 -0
- snappy/doc/_static/fonts/Lato/lato-bold.ttf +0 -0
- snappy/doc/_static/fonts/Lato/lato-bold.woff +0 -0
- snappy/doc/_static/fonts/Lato/lato-bold.woff2 +0 -0
- snappy/doc/_static/fonts/Lato/lato-bolditalic.eot +0 -0
- snappy/doc/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
- snappy/doc/_static/fonts/Lato/lato-bolditalic.woff +0 -0
- snappy/doc/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
- snappy/doc/_static/fonts/Lato/lato-italic.eot +0 -0
- snappy/doc/_static/fonts/Lato/lato-italic.ttf +0 -0
- snappy/doc/_static/fonts/Lato/lato-italic.woff +0 -0
- snappy/doc/_static/fonts/Lato/lato-italic.woff2 +0 -0
- snappy/doc/_static/fonts/Lato/lato-regular.eot +0 -0
- snappy/doc/_static/fonts/Lato/lato-regular.ttf +0 -0
- snappy/doc/_static/fonts/Lato/lato-regular.woff +0 -0
- snappy/doc/_static/fonts/Lato/lato-regular.woff2 +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
- snappy/doc/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
- snappy/doc/_static/jquery.js +2 -0
- snappy/doc/_static/js/badge_only.js +1 -0
- snappy/doc/_static/js/theme.js +1 -0
- snappy/doc/_static/js/versions.js +228 -0
- snappy/doc/_static/language_data.js +199 -0
- snappy/doc/_static/minus.png +0 -0
- snappy/doc/_static/plus.png +0 -0
- snappy/doc/_static/pygments.css +75 -0
- snappy/doc/_static/searchtools.js +620 -0
- snappy/doc/_static/snappy_furo.css +33 -0
- snappy/doc/_static/snappy_sphinx_rtd_theme.css +42 -0
- snappy/doc/_static/sphinx_highlight.js +154 -0
- snappy/doc/additional_classes.html +1500 -0
- snappy/doc/bugs.html +132 -0
- snappy/doc/censuses.html +427 -0
- snappy/doc/credits.html +181 -0
- snappy/doc/development.html +384 -0
- snappy/doc/genindex.html +1331 -0
- snappy/doc/index.html +262 -0
- snappy/doc/installing.html +346 -0
- snappy/doc/manifold.html +3452 -0
- snappy/doc/manifoldhp.html +180 -0
- snappy/doc/news.html +388 -0
- snappy/doc/objects.inv +0 -0
- snappy/doc/other.html +161 -0
- snappy/doc/platonic_census.html +375 -0
- snappy/doc/plink.html +210 -0
- snappy/doc/ptolemy.html +254 -0
- snappy/doc/ptolemy_classes.html +1144 -0
- snappy/doc/ptolemy_examples1.html +409 -0
- snappy/doc/ptolemy_examples2.html +471 -0
- snappy/doc/ptolemy_examples3.html +414 -0
- snappy/doc/ptolemy_examples4.html +195 -0
- snappy/doc/ptolemy_prelim.html +248 -0
- snappy/doc/py-modindex.html +165 -0
- snappy/doc/screenshots.html +141 -0
- snappy/doc/search.html +135 -0
- snappy/doc/searchindex.js +1 -0
- snappy/doc/snap.html +202 -0
- snappy/doc/snappy.html +181 -0
- snappy/doc/spherogram.html +1211 -0
- snappy/doc/todo.html +166 -0
- snappy/doc/triangulation.html +1584 -0
- snappy/doc/tutorial.html +159 -0
- snappy/doc/verify.html +330 -0
- snappy/doc/verify_internals.html +1235 -0
- snappy/drilling/__init__.py +456 -0
- snappy/drilling/barycentric.py +103 -0
- snappy/drilling/constants.py +5 -0
- snappy/drilling/crush.py +270 -0
- snappy/drilling/cusps.py +125 -0
- snappy/drilling/debug.py +242 -0
- snappy/drilling/epsilons.py +6 -0
- snappy/drilling/exceptions.py +55 -0
- snappy/drilling/moves.py +620 -0
- snappy/drilling/peripheral_curves.py +210 -0
- snappy/drilling/perturb.py +188 -0
- snappy/drilling/shorten.py +36 -0
- snappy/drilling/subdivide.py +274 -0
- snappy/drilling/test.py +23 -0
- snappy/drilling/test_cases.py +126 -0
- snappy/drilling/tracing.py +351 -0
- snappy/exceptions.py +26 -0
- snappy/export_stl.py +120 -0
- snappy/exterior_to_link/__init__.py +2 -0
- snappy/exterior_to_link/barycentric_geometry.py +463 -0
- snappy/exterior_to_link/exceptions.py +6 -0
- snappy/exterior_to_link/geodesic_map.json +14408 -0
- snappy/exterior_to_link/hyp_utils.py +112 -0
- snappy/exterior_to_link/link_projection.py +323 -0
- snappy/exterior_to_link/main.py +197 -0
- snappy/exterior_to_link/mcomplex_with_expansion.py +261 -0
- snappy/exterior_to_link/mcomplex_with_link.py +687 -0
- snappy/exterior_to_link/mcomplex_with_memory.py +162 -0
- snappy/exterior_to_link/pl_utils.py +491 -0
- snappy/exterior_to_link/put_in_S3.py +156 -0
- snappy/exterior_to_link/rational_linear_algebra.py +123 -0
- snappy/exterior_to_link/rational_linear_algebra_wrapped.py +135 -0
- snappy/exterior_to_link/simplify_to_base_tri.py +114 -0
- snappy/exterior_to_link/stored_moves.py +475 -0
- snappy/exterior_to_link/test.py +31 -0
- snappy/filedialog.py +28 -0
- snappy/geometric_structure/__init__.py +212 -0
- snappy/geometric_structure/cusp_neighborhood/__init__.py +3 -0
- snappy/geometric_structure/cusp_neighborhood/complex_cusp_cross_section.py +697 -0
- snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +484 -0
- snappy/geometric_structure/cusp_neighborhood/exceptions.py +42 -0
- snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +298 -0
- snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +159 -0
- snappy/geometric_structure/cusp_neighborhood/vertices.py +32 -0
- snappy/geometric_structure/geodesic/__init__.py +0 -0
- snappy/geometric_structure/geodesic/add_core_curves.py +152 -0
- snappy/geometric_structure/geodesic/avoid_core_curves.py +369 -0
- snappy/geometric_structure/geodesic/canonical_keys.py +52 -0
- snappy/geometric_structure/geodesic/check_away_from_core_curve.py +60 -0
- snappy/geometric_structure/geodesic/constants.py +6 -0
- snappy/geometric_structure/geodesic/exceptions.py +22 -0
- snappy/geometric_structure/geodesic/fixed_points.py +93 -0
- snappy/geometric_structure/geodesic/geodesic_start_point_info.py +435 -0
- snappy/geometric_structure/geodesic/graph_trace_helper.py +67 -0
- snappy/geometric_structure/geodesic/line.py +30 -0
- snappy/geometric_structure/geodesic/multiplicity.py +127 -0
- snappy/geometric_structure/geodesic/tiles_for_geodesic.py +101 -0
- snappy/geometric_structure/test.py +22 -0
- snappy/gui.py +121 -0
- snappy/horoviewer.py +443 -0
- snappy/hyperboloid/__init__.py +212 -0
- snappy/hyperboloid/distances.py +245 -0
- snappy/hyperboloid/horoball.py +19 -0
- snappy/hyperboloid/line.py +35 -0
- snappy/hyperboloid/point.py +9 -0
- snappy/hyperboloid/triangle.py +29 -0
- snappy/info_icon.gif +0 -0
- snappy/infowindow.py +65 -0
- snappy/isometry_signature.py +382 -0
- snappy/len_spec/__init__.py +596 -0
- snappy/len_spec/geodesic_info.py +110 -0
- snappy/len_spec/geodesic_key_info_dict.py +117 -0
- snappy/len_spec/geodesic_piece.py +143 -0
- snappy/len_spec/geometric_structure.py +182 -0
- snappy/len_spec/geometry.py +80 -0
- snappy/len_spec/length_spectrum_geodesic_info.py +170 -0
- snappy/len_spec/spine.py +206 -0
- snappy/len_spec/test.py +24 -0
- snappy/len_spec/test_cases.py +69 -0
- snappy/len_spec/tile.py +275 -0
- snappy/len_spec/word.py +86 -0
- snappy/manifolds/HTWKnots/alternating.gz +0 -0
- snappy/manifolds/HTWKnots/nonalternating.gz +0 -0
- snappy/manifolds/__init__.py +3 -0
- snappy/math_basics.py +176 -0
- snappy/matrix.py +525 -0
- snappy/number.py +657 -0
- snappy/numeric_output_checker.py +345 -0
- snappy/pari.py +41 -0
- snappy/phone_home.py +57 -0
- snappy/polyviewer.py +259 -0
- snappy/ptolemy/__init__.py +17 -0
- snappy/ptolemy/component.py +103 -0
- snappy/ptolemy/coordinates.py +2290 -0
- snappy/ptolemy/fieldExtensions.py +153 -0
- snappy/ptolemy/findLoops.py +473 -0
- snappy/ptolemy/geometricRep.py +59 -0
- snappy/ptolemy/homology.py +165 -0
- snappy/ptolemy/magma/default.magma_template +229 -0
- snappy/ptolemy/magma/radicalsOfPrimaryDecomposition.magma_template +79 -0
- snappy/ptolemy/manifoldMethods.py +395 -0
- snappy/ptolemy/matrix.py +350 -0
- snappy/ptolemy/numericalSolutionsToGroebnerBasis.py +113 -0
- snappy/ptolemy/polynomial.py +857 -0
- snappy/ptolemy/processComponents.py +173 -0
- snappy/ptolemy/processFileBase.py +247 -0
- snappy/ptolemy/processFileDispatch.py +46 -0
- snappy/ptolemy/processMagmaFile.py +392 -0
- snappy/ptolemy/processRurFile.py +150 -0
- snappy/ptolemy/ptolemyGeneralizedObstructionClass.py +102 -0
- snappy/ptolemy/ptolemyObstructionClass.py +64 -0
- snappy/ptolemy/ptolemyVariety.py +1029 -0
- snappy/ptolemy/ptolemyVarietyPrimeIdealGroebnerBasis.py +140 -0
- snappy/ptolemy/reginaWrapper.py +698 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/regina_testing_files_generalized/m015__sl3_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/rur.py +545 -0
- snappy/ptolemy/solutionsToPrimeIdealGroebnerBasis.py +277 -0
- snappy/ptolemy/test.py +1126 -0
- snappy/ptolemy/testing_files/3_1__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/3_1__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/4_1__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/4_1__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/4_1__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/4_1__sl4_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/4_1__sl4_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/5_2__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/5_2__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c2.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c3.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c4.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c5.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c6.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/DT_mcbbiceaibjklmdfgh__sl2_c7.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c0.magma_out +95 -0
- snappy/ptolemy/testing_files/data/pgl2/OrientableCuspedCensus/03_tetrahedra/m019__sl2_c1.magma_out +95 -0
- snappy/ptolemy/testing_files/m015__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c2.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c3.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c4.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c5.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c6.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/m135__sl2_c7.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/s000__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/s000__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/t00000__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/t00000__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/v0000__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/v0000__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/v0000__sl2_c2.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files/v0000__sl2_c3.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m003__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m003__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m003__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m003__sl3_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m004__sl2_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m004__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m015__sl2_c1.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_generalized/m015__sl3_c0.magma_out.bz2 +0 -0
- snappy/ptolemy/testing_files_rur/m052__sl3_c0.rur.bz2 +0 -0
- snappy/ptolemy/utilities.py +236 -0
- snappy/raytracing/__init__.py +64 -0
- snappy/raytracing/additional_horospheres.py +64 -0
- snappy/raytracing/additional_len_spec_choices.py +63 -0
- snappy/raytracing/cohomology_fractal.py +197 -0
- snappy/raytracing/eyeball.py +123 -0
- snappy/raytracing/finite_raytracing_data.py +237 -0
- snappy/raytracing/finite_viewer.py +590 -0
- snappy/raytracing/geodesic_tube_info.py +174 -0
- snappy/raytracing/geodesics.py +246 -0
- snappy/raytracing/geodesics_window.py +258 -0
- snappy/raytracing/gui_utilities.py +293 -0
- snappy/raytracing/hyperboloid_navigation.py +556 -0
- snappy/raytracing/hyperboloid_utilities.py +234 -0
- snappy/raytracing/ideal_raytracing_data.py +592 -0
- snappy/raytracing/inside_viewer.py +974 -0
- snappy/raytracing/pack.py +22 -0
- snappy/raytracing/raytracing_data.py +126 -0
- snappy/raytracing/raytracing_view.py +454 -0
- snappy/raytracing/shaders/Eye.png +0 -0
- snappy/raytracing/shaders/NonGeometric.png +0 -0
- snappy/raytracing/shaders/__init__.py +101 -0
- snappy/raytracing/shaders/fragment.glsl +1744 -0
- snappy/raytracing/test.py +29 -0
- snappy/raytracing/tooltip.py +146 -0
- snappy/raytracing/upper_halfspace_utilities.py +98 -0
- snappy/raytracing/view_scale_controller.py +98 -0
- snappy/raytracing/zoom_slider/__init__.py +263 -0
- snappy/raytracing/zoom_slider/inward.png +0 -0
- snappy/raytracing/zoom_slider/inward18.png +0 -0
- snappy/raytracing/zoom_slider/outward.png +0 -0
- snappy/raytracing/zoom_slider/outward18.png +0 -0
- snappy/raytracing/zoom_slider/test.py +20 -0
- snappy/sage_helper.py +117 -0
- snappy/settings.py +409 -0
- snappy/shell.py +53 -0
- snappy/snap/__init__.py +114 -0
- snappy/snap/character_varieties.py +375 -0
- snappy/snap/find_field.py +372 -0
- snappy/snap/fundamental_polyhedron.py +569 -0
- snappy/snap/generators.py +39 -0
- snappy/snap/interval_reps.py +81 -0
- snappy/snap/kernel_structures.py +128 -0
- snappy/snap/mcomplex_base.py +18 -0
- snappy/snap/nsagetools.py +702 -0
- snappy/snap/peripheral/__init__.py +1 -0
- snappy/snap/peripheral/dual_cellulation.py +219 -0
- snappy/snap/peripheral/link.py +127 -0
- snappy/snap/peripheral/peripheral.py +159 -0
- snappy/snap/peripheral/surface.py +522 -0
- snappy/snap/peripheral/test.py +35 -0
- snappy/snap/polished_reps.py +335 -0
- snappy/snap/shapes.py +152 -0
- snappy/snap/slice_obs_HKL.py +668 -0
- snappy/snap/t3mlite/__init__.py +2 -0
- snappy/snap/t3mlite/arrow.py +243 -0
- snappy/snap/t3mlite/corner.py +22 -0
- snappy/snap/t3mlite/edge.py +172 -0
- snappy/snap/t3mlite/face.py +37 -0
- snappy/snap/t3mlite/files.py +211 -0
- snappy/snap/t3mlite/homology.py +53 -0
- snappy/snap/t3mlite/linalg.py +419 -0
- snappy/snap/t3mlite/mcomplex.py +1499 -0
- snappy/snap/t3mlite/perm4.py +320 -0
- snappy/snap/t3mlite/setup.py +12 -0
- snappy/snap/t3mlite/simplex.py +199 -0
- snappy/snap/t3mlite/spun.py +297 -0
- snappy/snap/t3mlite/surface.py +519 -0
- snappy/snap/t3mlite/test.py +20 -0
- snappy/snap/t3mlite/test_vs_regina.py +86 -0
- snappy/snap/t3mlite/tetrahedron.py +109 -0
- snappy/snap/t3mlite/vertex.py +42 -0
- snappy/snap/test.py +134 -0
- snappy/snap/utilities.py +288 -0
- snappy/test.py +209 -0
- snappy/test_cases.py +263 -0
- snappy/testing.py +131 -0
- snappy/tiling/__init__.py +2 -0
- snappy/tiling/canonical_key_dict.py +59 -0
- snappy/tiling/dict_based_set.py +79 -0
- snappy/tiling/floor.py +49 -0
- snappy/tiling/hyperboloid_dict.py +54 -0
- snappy/tiling/iter_utils.py +78 -0
- snappy/tiling/lifted_tetrahedron.py +22 -0
- snappy/tiling/lifted_tetrahedron_set.py +54 -0
- snappy/tiling/real_hash_dict.py +164 -0
- snappy/tiling/test.py +23 -0
- snappy/tiling/tile.py +215 -0
- snappy/tiling/triangle.py +33 -0
- snappy/tkterminal.py +920 -0
- snappy/twister/__init__.py +20 -0
- snappy/twister/main.py +646 -0
- snappy/twister/surfaces/S_0_1 +3 -0
- snappy/twister/surfaces/S_0_2 +3 -0
- snappy/twister/surfaces/S_0_4 +7 -0
- snappy/twister/surfaces/S_0_4_Lantern +8 -0
- snappy/twister/surfaces/S_1 +3 -0
- snappy/twister/surfaces/S_1_1 +4 -0
- snappy/twister/surfaces/S_1_2 +5 -0
- snappy/twister/surfaces/S_1_2_5 +6 -0
- snappy/twister/surfaces/S_2 +6 -0
- snappy/twister/surfaces/S_2_1 +8 -0
- snappy/twister/surfaces/S_2_heeg +10 -0
- snappy/twister/surfaces/S_3 +8 -0
- snappy/twister/surfaces/S_3_1 +10 -0
- snappy/twister/surfaces/S_4_1 +12 -0
- snappy/twister/surfaces/S_5_1 +14 -0
- snappy/twister/surfaces/heeg_fig8 +9 -0
- snappy/twister/twister_core.cpython-310-darwin.so +0 -0
- snappy/upper_halfspace/__init__.py +146 -0
- snappy/upper_halfspace/ideal_point.py +26 -0
- snappy/verify/__init__.py +13 -0
- snappy/verify/canonical.py +542 -0
- snappy/verify/complex_volume/__init__.py +18 -0
- snappy/verify/complex_volume/adjust_torsion.py +86 -0
- snappy/verify/complex_volume/closed.py +168 -0
- snappy/verify/complex_volume/compute_ptolemys.py +90 -0
- snappy/verify/complex_volume/cusped.py +56 -0
- snappy/verify/complex_volume/extended_bloch.py +201 -0
- snappy/verify/cusp_translations.py +85 -0
- snappy/verify/edge_equations.py +80 -0
- snappy/verify/exceptions.py +254 -0
- snappy/verify/hyperbolicity.py +224 -0
- snappy/verify/interval_newton_shapes_engine.py +523 -0
- snappy/verify/interval_tree.py +400 -0
- snappy/verify/krawczyk_shapes_engine.py +518 -0
- snappy/verify/maximal_cusp_area_matrix/__init__.py +46 -0
- snappy/verify/maximal_cusp_area_matrix/cusp_tiling_engine.py +419 -0
- snappy/verify/maximal_cusp_area_matrix/cusp_translate_engine.py +153 -0
- snappy/verify/real_algebra.py +286 -0
- snappy/verify/shapes.py +25 -0
- snappy/verify/short_slopes.py +200 -0
- snappy/verify/square_extensions.py +1005 -0
- snappy/verify/test.py +78 -0
- snappy/verify/upper_halfspace/__init__.py +9 -0
- snappy/verify/upper_halfspace/extended_matrix.py +100 -0
- snappy/verify/upper_halfspace/finite_point.py +283 -0
- snappy/verify/upper_halfspace/ideal_point.py +426 -0
- snappy/verify/volume.py +128 -0
- snappy/version.py +2 -0
- snappy-3.2.dist-info/METADATA +58 -0
- snappy-3.2.dist-info/RECORD +503 -0
- snappy-3.2.dist-info/WHEEL +5 -0
- snappy-3.2.dist-info/entry_points.txt +2 -0
- snappy-3.2.dist-info/top_level.txt +28 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
def pos_tets(manifold):
|
2
|
+
return manifold.solution_type() == 'all tetrahedra positively oriented'
|
3
|
+
|
4
|
+
|
5
|
+
def basic_improve_tri(manifold, tries=10):
|
6
|
+
M = manifold.copy()
|
7
|
+
for i in range(tries):
|
8
|
+
if pos_tets(M):
|
9
|
+
return M
|
10
|
+
M.randomize()
|
11
|
+
return manifold.copy()
|
12
|
+
|
13
|
+
|
14
|
+
def improved_triangulation(manifold, tries=10):
|
15
|
+
M = basic_improve_tri(manifold, tries=tries)
|
16
|
+
if pos_tets(M):
|
17
|
+
return M
|
18
|
+
|
19
|
+
curves = M.dual_curves()
|
20
|
+
for i, c in zip(range(tries), curves):
|
21
|
+
D = M.drill(c)
|
22
|
+
D.dehn_fill((1, 0), M.num_cusps())
|
23
|
+
F = D.filled_triangulation()
|
24
|
+
if pos_tets(F):
|
25
|
+
return F
|
26
|
+
|
27
|
+
return manifold.copy()
|
28
|
+
|
29
|
+
|
30
|
+
def is_isometric_to_with_effort(A, B, return_isometries=False, tries=10):
|
31
|
+
A = improved_triangulation(A, tries=tries)
|
32
|
+
B = improved_triangulation(B, tries=tries)
|
33
|
+
try:
|
34
|
+
return A.is_isometric_to(B, return_isometries=return_isometries)
|
35
|
+
except RuntimeError: # SnapPea kernel failed
|
36
|
+
return []
|
37
|
+
|
38
|
+
|
39
|
+
def orient_pres(isometry):
|
40
|
+
"""
|
41
|
+
>>> M = Manifold('K4a1')
|
42
|
+
>>> kinds = {orient_pres(iso) for iso in M.is_isometric_to(M, True)}
|
43
|
+
>>> sorted(kinds)
|
44
|
+
[False, True]
|
45
|
+
"""
|
46
|
+
return isometry.cusp_maps()[0].det() > 0
|
47
|
+
|
48
|
+
|
49
|
+
def are_orient_pres_isometric_as_ordered_links(A, B):
|
50
|
+
"""
|
51
|
+
All of the following manifolds isometric, but not as ordered links
|
52
|
+
|
53
|
+
>>> A = Manifold('L10n1')
|
54
|
+
>>> B = Manifold('L7a2')
|
55
|
+
>>> C = Manifold('L10n1')
|
56
|
+
>>> C._reindex_cusps([1, 0])
|
57
|
+
>>> are_orient_pres_isometric_as_ordered_links(A, B)
|
58
|
+
False
|
59
|
+
>>> are_orient_pres_isometric_as_ordered_links(A, C)
|
60
|
+
False
|
61
|
+
>>> are_orient_pres_isometric_as_ordered_links(C, C)
|
62
|
+
True
|
63
|
+
"""
|
64
|
+
isos = is_isometric_to_with_effort(A, B, return_isometries=True)
|
65
|
+
isos = [iso for iso in isos if iso.extends_to_link() and orient_pres(iso)]
|
66
|
+
ident = list(range(A.num_cusps()))
|
67
|
+
return any(iso.cusp_images() == ident for iso in isos)
|
68
|
+
|
69
|
+
|
70
|
+
def orientation_preserving_link_isometries(A, B, tries=100):
|
71
|
+
isos = is_isometric_to_with_effort(A, B, return_isometries=True, tries=tries)
|
72
|
+
ans = any(iso.extends_to_link() for iso in isos)
|
73
|
+
if not ans:
|
74
|
+
A, B = A.high_precision(), B.high_precision()
|
75
|
+
isos = is_isometric_to_with_effort(A, B, return_isometries=True, tries=tries)
|
76
|
+
good_isos = [iso for iso in isos if iso.extends_to_link() and orient_pres(iso)]
|
77
|
+
if good_isos:
|
78
|
+
return good_isos[0]
|
79
|
+
|
80
|
+
|
81
|
+
def reorder_link_components(link, perm):
|
82
|
+
"""
|
83
|
+
This link has three components, which are in order a trefoil, the
|
84
|
+
figure 8, and an unknot.
|
85
|
+
|
86
|
+
>>> L0 = Manifold('DT[uciicOFRTIQKUDsMpgBelAnjCH.000001011100110110010]').link()
|
87
|
+
>>> [len(L0.sublink([i]).crossings) for i in range(3)]
|
88
|
+
[3, 4, 0]
|
89
|
+
|
90
|
+
perm is the permutation of {0, 1, ... , num_comps - 1} where
|
91
|
+
perm[old_comp_index] = new_comp_index.
|
92
|
+
|
93
|
+
>>> L1 = reorder_link_components(L0, [1, 2, 0])
|
94
|
+
>>> [len(L1.sublink([i]).crossings) for i in range(3)]
|
95
|
+
[0, 3, 4]
|
96
|
+
>>> L2 = reorder_link_components(L0, [2, 0, 1])
|
97
|
+
>>> [len(L2.sublink([i]).crossings) for i in range(3)]
|
98
|
+
[4, 0, 3]
|
99
|
+
"""
|
100
|
+
n = len(link.link_components)
|
101
|
+
assert len(perm) == n and link.unlinked_unknot_components == 0
|
102
|
+
L = link.copy()
|
103
|
+
component_starts = n * [None]
|
104
|
+
for a, b in enumerate(perm):
|
105
|
+
component_starts[b] = L.link_components[a][0]
|
106
|
+
L._build_components(component_starts)
|
107
|
+
return L
|
108
|
+
|
109
|
+
|
110
|
+
if __name__ == '__main__':
|
111
|
+
import doctest
|
112
|
+
doctest.testmod()
|
@@ -0,0 +1,323 @@
|
|
1
|
+
"""
|
2
|
+
For a PL link in R^3, produce a link diagram by projecting it onto a
|
3
|
+
plane (by default a randomly chosen one). Also includes code for
|
4
|
+
simplifying a PL link by basic straightening moves.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import spherogram
|
8
|
+
import random
|
9
|
+
import itertools
|
10
|
+
from . import pl_utils
|
11
|
+
from .rational_linear_algebra import QQ, Matrix, Vector3
|
12
|
+
from .exceptions import GeneralPositionError
|
13
|
+
|
14
|
+
|
15
|
+
def fig8_points():
|
16
|
+
# Extracted from put_in_S3.example10, used for testing.
|
17
|
+
pts = [(1564, 148, 0, 1117), (765, 1137, 786, 1117), (1117, 1882, 1490, 1117),
|
18
|
+
(1469, 1137, 786, 1117), (698, 280, 0, 1117), (1166, 372, -744, 1117),
|
19
|
+
(1862, 372, -1440, 1117), (1514, 1068, -744, 1117), (380, 198, 0, 279),
|
20
|
+
(564, 604, 604, 559), (701, 219, 438, 1117), (-679, -241, 0, 1117),
|
21
|
+
(460, 679, -482, 1117)]
|
22
|
+
return [[Vector3([a, b, c])/d for a, b, c, d in pts]]
|
23
|
+
|
24
|
+
|
25
|
+
def twist_knot_points():
|
26
|
+
"""
|
27
|
+
The knot 5_2 = K5a1
|
28
|
+
"""
|
29
|
+
pts = [(25, 36, 5), (14, 36, -3), (14, 14, 0), (47, 14, 0), (47, 25, 0),
|
30
|
+
(3, 25, 0), (3, 47, 0), (36, 47, -6), (36, 3, 4), (25, 3, -5)]
|
31
|
+
return [[Vector3(pt) for pt in pts]]
|
32
|
+
|
33
|
+
|
34
|
+
def proj(point): # projection onto z = 0
|
35
|
+
return Vector3([point[i] for i in [0,1]]+[0])
|
36
|
+
|
37
|
+
|
38
|
+
def random_transform(steps=5):
|
39
|
+
"""
|
40
|
+
Generators of SL(3, Z) from
|
41
|
+
|
42
|
+
https://doi.org/10.1090/S0002-9939-1992-1079696-5
|
43
|
+
|
44
|
+
>>> random_transform(5).det()
|
45
|
+
1
|
46
|
+
"""
|
47
|
+
I = Matrix([[1, 0, 0], [0, 1, 0], [ 0, 0, 1]])
|
48
|
+
X = Matrix([[0, 1, 0], [0, 0, 1], [ 1, 0, 0]])
|
49
|
+
Y = Matrix([[1, 0, 1], [0, -1, -1], [ 0, 1, 0]])
|
50
|
+
Z = Matrix([[0, 1, 0], [1, 0, 0], [-1, -1, -1]])
|
51
|
+
# X and Y have order two and Z order three, so there are
|
52
|
+
# symmetric gens:
|
53
|
+
gens = [I, X, X*X, Y, Y*Y, Z, Z]
|
54
|
+
ans = I
|
55
|
+
for s in range(steps):
|
56
|
+
ans = ans * random.choice(gens)
|
57
|
+
return ans
|
58
|
+
|
59
|
+
|
60
|
+
def norm_sq(v):
|
61
|
+
return sum(x**2 for x in v)
|
62
|
+
|
63
|
+
|
64
|
+
def min_dist_sq(points):
|
65
|
+
pairs = itertools.combinations(points, 2)
|
66
|
+
return min(norm_sq(p - q) for p, q in pairs)
|
67
|
+
|
68
|
+
|
69
|
+
def straightenable_tri(points, extra_arcs=None):
|
70
|
+
if extra_arcs is None:
|
71
|
+
extra_arcs = []
|
72
|
+
n = len(points)
|
73
|
+
for i in range(n):
|
74
|
+
indices = i, (i + 1) % n, (i + 2) % n
|
75
|
+
tri = [points[k] for k in indices]
|
76
|
+
other_arcs = [(points[k], points[(k+1) % n])
|
77
|
+
for k in range(n) if k not in indices[:2]]
|
78
|
+
if pl_utils.colinear(*tri):
|
79
|
+
return indices
|
80
|
+
M = pl_utils.standardize_bend_matrix(*tri)
|
81
|
+
if all(pl_utils.can_straighten_bend(a, tri, False, M)
|
82
|
+
for a in other_arcs + extra_arcs):
|
83
|
+
return indices
|
84
|
+
|
85
|
+
|
86
|
+
def arcs_from_points(points_list):
|
87
|
+
arcs = []
|
88
|
+
for p in points_list:
|
89
|
+
n = len(p)
|
90
|
+
arcs += [(p[k], p[(k+1) % n]) for k in range(n)]
|
91
|
+
return arcs
|
92
|
+
|
93
|
+
|
94
|
+
def straighten_knot(points):
|
95
|
+
while True:
|
96
|
+
tri = straightenable_tri(points)
|
97
|
+
if tri:
|
98
|
+
a, b, c = tri
|
99
|
+
# We shuffle is so that we look for next triangle in less examined location
|
100
|
+
if a < b < c:
|
101
|
+
points = points[c:] + points[:b]
|
102
|
+
else:
|
103
|
+
points = points[:b] + points[b + 1:]
|
104
|
+
else:
|
105
|
+
break
|
106
|
+
return points
|
107
|
+
|
108
|
+
|
109
|
+
def straighten_link(points_list):
|
110
|
+
for i in range(len(points_list)):
|
111
|
+
other_points = points_list.copy()
|
112
|
+
del other_points[i]
|
113
|
+
other_arcs = arcs_from_points(other_points)
|
114
|
+
while True:
|
115
|
+
points = points_list[i]
|
116
|
+
tri = straightenable_tri(points, other_arcs)
|
117
|
+
if tri:
|
118
|
+
a, b, c = tri
|
119
|
+
if a < b < c:
|
120
|
+
points = points[c:] + points[:b]
|
121
|
+
else:
|
122
|
+
points = points[:b] + points[b + 1:]
|
123
|
+
else:
|
124
|
+
break
|
125
|
+
points_list[i] = points
|
126
|
+
return points_list
|
127
|
+
|
128
|
+
|
129
|
+
class Arc():
|
130
|
+
"""
|
131
|
+
An arc from point a to point b where a and b are labeled by i and j.
|
132
|
+
"""
|
133
|
+
def __init__(self, a, i, b, j, label):
|
134
|
+
self.a, self.i, self.b, self.j, self.label = a, i, b, j, label
|
135
|
+
self.proj = a[:2], b[:2]
|
136
|
+
self.crossings = []
|
137
|
+
|
138
|
+
def __getitem__(self, index):
|
139
|
+
return [self.a, self.b][index]
|
140
|
+
|
141
|
+
def add_crossing(self, crossing, t):
|
142
|
+
self.crossings.append((t, crossing))
|
143
|
+
try:
|
144
|
+
self.crossings.sort()
|
145
|
+
except TypeError:
|
146
|
+
raise GeneralPositionError('Two crossings on top of one another')
|
147
|
+
|
148
|
+
|
149
|
+
class Crossing():
|
150
|
+
def __init__(self, over_arc, under_arc, s, t, label):
|
151
|
+
self.over, self.under, self.label = over_arc, under_arc, label
|
152
|
+
self.s, self.t = s, t
|
153
|
+
a, b = over_arc.proj
|
154
|
+
u, v = under_arc.proj
|
155
|
+
M = Matrix([b - a, v - u])
|
156
|
+
self.sign = 1 if M.det() > 0 else -1
|
157
|
+
e = 1e-12
|
158
|
+
assert (1 - s)*a + s*b == (1 - t)*u + t*v
|
159
|
+
assert ((e < s < 1 - e) and (e < t < 1 - e))
|
160
|
+
over_arc.add_crossing(self, s)
|
161
|
+
under_arc.add_crossing(self, t)
|
162
|
+
|
163
|
+
|
164
|
+
class LinkProjection():
|
165
|
+
"""
|
166
|
+
The idea is to apply a unimodular matrix and to project the knot
|
167
|
+
onto the z=0 plane. We then recover the crossing data by finding
|
168
|
+
points that intersect after projecting then taking the over
|
169
|
+
crossing to be the lift with larger z coord.
|
170
|
+
|
171
|
+
>>> pts = fig8_points()
|
172
|
+
>>> kp = LinkProjection(pts)
|
173
|
+
>>> K = kp.link()
|
174
|
+
>>> K.exterior().identify()
|
175
|
+
[m004(0,0), 4_1(0,0), K2_1(0,0), K4a1(0,0), otet02_00001(0,0)]
|
176
|
+
|
177
|
+
>>> M = Matrix([[0,1,1],[1,1,0],[0,0,2]])
|
178
|
+
>>> kp = LinkProjection(pts, M)
|
179
|
+
>>> K = kp.link()
|
180
|
+
>>> K.exterior().identify()
|
181
|
+
[m004(0,0), 4_1(0,0), K2_1(0,0), K4a1(0,0), otet02_00001(0,0)]
|
182
|
+
|
183
|
+
>>> kp = LinkProjection(twist_knot_points())
|
184
|
+
>>> K = kp.link()
|
185
|
+
>>> M = Manifold('K5a1')
|
186
|
+
>>> isos = M.is_isometric_to(K.exterior(), True)
|
187
|
+
>>> {iso.cusp_maps()[0].det() for iso in isos}
|
188
|
+
{1}
|
189
|
+
"""
|
190
|
+
|
191
|
+
def __init__(self, points_by_component, mat=None):
|
192
|
+
# mat is a matrix, we transform the points by mat then project
|
193
|
+
# onto z = 0 plane, plane is point and vector
|
194
|
+
if mat is None:
|
195
|
+
mat = Matrix([[0, -2, -1], [1, 2, 2], [-1, 1, 0]])
|
196
|
+
self.mat = mat
|
197
|
+
|
198
|
+
components = []
|
199
|
+
for component_points in points_by_component:
|
200
|
+
start = sum(len(C) for C in components)
|
201
|
+
comp_len = len(component_points)
|
202
|
+
components.append(list(range(start, start + comp_len)))
|
203
|
+
|
204
|
+
self.components = components
|
205
|
+
all_points = sum(points_by_component, [])
|
206
|
+
self.points = [mat*p for p in all_points]
|
207
|
+
self.projected_points = [proj(p) for p in self.points]
|
208
|
+
|
209
|
+
# Check that nothing is too degenerate:
|
210
|
+
assert min_dist_sq(self.points) > 1e-15
|
211
|
+
if min_dist_sq(self.projected_points) < 1e-16:
|
212
|
+
raise GeneralPositionError('Projection is nearly degenerate')
|
213
|
+
|
214
|
+
self._setup_crossings()
|
215
|
+
|
216
|
+
def _setup_crossings(self):
|
217
|
+
# compute the over and under crossings of the link projection
|
218
|
+
|
219
|
+
pts = self.points
|
220
|
+
crossings, arcs = [], []
|
221
|
+
for component in self.components:
|
222
|
+
successive_pairs = [(c, component[(i + 1) % len(component)]) for
|
223
|
+
i, c in enumerate(component)]
|
224
|
+
arcs += [Arc(pts[i], i, pts[j], j, i) for i, j in successive_pairs]
|
225
|
+
|
226
|
+
for A, B in itertools.combinations(arcs, 2):
|
227
|
+
a = proj(A[0]), proj(A[1])
|
228
|
+
b = proj(B[0]), proj(B[1])
|
229
|
+
|
230
|
+
# When A and B are successive arcs, we just need to test
|
231
|
+
# things are sufficiently generic.
|
232
|
+
|
233
|
+
if A.j == B.i:
|
234
|
+
# assert not near_reverse(a[0], a[1], b[1])
|
235
|
+
continue
|
236
|
+
elif B.j == A.i:
|
237
|
+
# assert not near_reverse(b[0], b[1], a[1])
|
238
|
+
continue
|
239
|
+
elif pl_utils.segments_meet_not_at_endpoint(a, b):
|
240
|
+
# There is a crossing and now we figure out which arc
|
241
|
+
# crosses over the other.
|
242
|
+
|
243
|
+
# find the intersection point
|
244
|
+
M = Matrix([a[1]-a[0], b[0]-b[1]]).transpose()
|
245
|
+
if M.rank() != 2:
|
246
|
+
raise GeneralPositionError('Segments overlap on their interiors')
|
247
|
+
s, t = M.solve_right(b[0]-a[0])
|
248
|
+
e = 1e-12
|
249
|
+
if not ((e < s < 1 - e) and (e < t < 1 - e)):
|
250
|
+
raise GeneralPositionError('Intersection too near the end of one segment')
|
251
|
+
|
252
|
+
x_a = (1-s)*A[0] + s*A[1] # lift of intersection to A
|
253
|
+
x_b = (1-t)*B[0] + t*B[1] # lift of intersection to B
|
254
|
+
|
255
|
+
# make sure our lifts project to same point in plane
|
256
|
+
assert norm_sq(proj(x_a - x_b)) < 1e-5
|
257
|
+
|
258
|
+
# whichever arc contains the higher intersection
|
259
|
+
# lifted point is the over crossing arc
|
260
|
+
height_a = x_a[2]
|
261
|
+
height_b = x_b[2]
|
262
|
+
|
263
|
+
assert abs(height_a - height_b) > 1e-14
|
264
|
+
if height_a > height_b:
|
265
|
+
crossings.append(Crossing(A, B, s, t, len(crossings)))
|
266
|
+
else:
|
267
|
+
crossings.append(Crossing(B, A, t, s, len(crossings)))
|
268
|
+
|
269
|
+
self.crossings, self.arcs = crossings, arcs
|
270
|
+
|
271
|
+
def link(self):
|
272
|
+
# For bookkeeping, we use a Strand for each point the
|
273
|
+
# projection, together with the obviously needed crossings.
|
274
|
+
|
275
|
+
strands = [spherogram.Strand(label='S%d' % i)
|
276
|
+
for i, p in enumerate(self.points)]
|
277
|
+
crossings = [spherogram.Crossing(label='C%d' % i)
|
278
|
+
for i, c in enumerate(self.crossings)]
|
279
|
+
|
280
|
+
for arc in self.arcs:
|
281
|
+
A, a = strands[arc.i], 1
|
282
|
+
for t, C in arc.crossings:
|
283
|
+
B = crossings[C.label]
|
284
|
+
if arc == C.over:
|
285
|
+
b = 3 if C.sign == 1 else 1
|
286
|
+
else:
|
287
|
+
b = 0
|
288
|
+
# glue up
|
289
|
+
A[a] = B[b]
|
290
|
+
A, a = B, (b + 2) % 4
|
291
|
+
|
292
|
+
# glue to Strand corresponding to the endpoint of the arc.
|
293
|
+
B, b = strands[arc.j], 0
|
294
|
+
A[a] = B[b]
|
295
|
+
|
296
|
+
L = spherogram.Link(strands + crossings)
|
297
|
+
return L
|
298
|
+
|
299
|
+
|
300
|
+
def project_to_diagram(link_in_R3):
|
301
|
+
"""
|
302
|
+
>>> project_to_diagram(fig8_points())
|
303
|
+
<Link: 1 comp; 4 cross>
|
304
|
+
"""
|
305
|
+
diagram = None
|
306
|
+
for mat_size in [None, 15, 25, 15, 25, 15, 25, 100, 250, 100, 250, 500, 500]:
|
307
|
+
if mat_size is None:
|
308
|
+
proj_mat = Matrix([[3, 1, 0], [1, -1, 5], [0, 0, -1]])
|
309
|
+
else:
|
310
|
+
proj_mat = random_transform(mat_size)
|
311
|
+
try:
|
312
|
+
projection = LinkProjection(link_in_R3, proj_mat)
|
313
|
+
diagram = projection.link()
|
314
|
+
break
|
315
|
+
except GeneralPositionError as e:
|
316
|
+
pass
|
317
|
+
|
318
|
+
return diagram
|
319
|
+
|
320
|
+
|
321
|
+
if __name__ == '__main__':
|
322
|
+
import doctest
|
323
|
+
print(doctest.testmod())
|
@@ -0,0 +1,197 @@
|
|
1
|
+
"""
|
2
|
+
Defines the main function `exterior_to_link`.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import random
|
6
|
+
import typing
|
7
|
+
from .exceptions import ExteriorToLinkError
|
8
|
+
from .simplify_to_base_tri import good_simplification
|
9
|
+
from . import put_in_S3
|
10
|
+
from . import link_projection
|
11
|
+
from .rational_linear_algebra import Matrix
|
12
|
+
from . import hyp_utils
|
13
|
+
from ..SnapPy import set_rand_seed
|
14
|
+
|
15
|
+
|
16
|
+
def filled_is_3sphere(manifold):
|
17
|
+
"""
|
18
|
+
>>> isosig = 'nLvLLLPQQkcfejimhklkmlkmuphkvuoupilhhv_Bbba(1, 0)'
|
19
|
+
>>> filled_is_3sphere(Manifold(isosig))
|
20
|
+
True
|
21
|
+
>>> filled_is_3sphere(Triangulation('m004(1, 2)'))
|
22
|
+
False
|
23
|
+
"""
|
24
|
+
if hasattr(manifold, 'without_hyperbolic_structure'):
|
25
|
+
T = manifold.without_hyperbolic_structure()
|
26
|
+
else:
|
27
|
+
T = manifold.copy()
|
28
|
+
for i in range(T.num_cusps()):
|
29
|
+
if T.cusp_info(i).is_complete:
|
30
|
+
T.dehn_fill((1, 0), i)
|
31
|
+
|
32
|
+
for i in range(10):
|
33
|
+
if T.fundamental_group().num_generators() == 0:
|
34
|
+
return True
|
35
|
+
F = T.filled_triangulation()
|
36
|
+
if F.fundamental_group().num_generators() == 0:
|
37
|
+
return True
|
38
|
+
T.randomize()
|
39
|
+
|
40
|
+
return False
|
41
|
+
|
42
|
+
|
43
|
+
def exterior_to_link(manifold,
|
44
|
+
verbose : bool = False,
|
45
|
+
check_input : bool = True,
|
46
|
+
check_answer : bool = True,
|
47
|
+
careful_perturbation : bool = True,
|
48
|
+
simplify_link : bool = True,
|
49
|
+
pachner_search_tries :int = 10,
|
50
|
+
seed : typing.Optional[int] = None) -> 'Link':
|
51
|
+
"""
|
52
|
+
For a triangulation of the exterior of a link in the 3-sphere,
|
53
|
+
return a planar diagram for the link. The peripheral curves whose
|
54
|
+
Dehn filling is the 3-sphere are **part of the input**, specified
|
55
|
+
by either:
|
56
|
+
|
57
|
+
a. If no cusp is filled, then they are the meridians of the
|
58
|
+
current peripheral curves.
|
59
|
+
|
60
|
+
b. If every cusp is filled, then they are the current Dehn filling
|
61
|
+
curves.
|
62
|
+
|
63
|
+
In particular, it does **not** try to determine whether there exist
|
64
|
+
fillings on the input which give the 3-sphere. Example usage:
|
65
|
+
|
66
|
+
>>> M = Manifold('m016')
|
67
|
+
>>> L = exterior_to_link(M)
|
68
|
+
>>> L.exterior().is_isometric_to(M)
|
69
|
+
True
|
70
|
+
|
71
|
+
The algorithm used is that of `Dunfield, Obeidin, and Rudd
|
72
|
+
<https://arxiv.org/abs/2112.03251>`_. The optional arguments are
|
73
|
+
as follows.
|
74
|
+
|
75
|
+
* ``verbose``: When ``True``, prints progress updates as the algorithm
|
76
|
+
goes along.
|
77
|
+
|
78
|
+
* ``check_input``: When ``True`` (the default), first checks that the
|
79
|
+
fundamental group of the specified Dehn filling is trivial. As
|
80
|
+
it doesn't try too hard to simplify the group presentation, it
|
81
|
+
can happen that this check fails but the algorithm still finds a
|
82
|
+
diagram if you pass ``check_input=False``.
|
83
|
+
|
84
|
+
* ``check_answer``: When ``True`` (the default), take the exterior of
|
85
|
+
the final link diagram and use ``Manifold.is_isometric_to`` to
|
86
|
+
confirm that it is homeomorphic to the input. If the input is
|
87
|
+
not hyperbolic or is very large, this check may fail even though
|
88
|
+
the diagram is correct.
|
89
|
+
|
90
|
+
* ``careful_perturbation``: The rational coordinates of the
|
91
|
+
intermediate PL links are periodically rounded to control the
|
92
|
+
size of their denominators. When ``careful_perturbation=True``
|
93
|
+
(the default), computations are performed to ensure this
|
94
|
+
rounding does not change the isotopy class of the link.
|
95
|
+
|
96
|
+
* ``simplify_link``: When ``True`` (the default), uses
|
97
|
+
``Link.simplify('global')`` to minimize the size of the final
|
98
|
+
diagram; otherwise, it just does ``basic`` simplifications, which
|
99
|
+
can be much faster if the initial link is complicated.
|
100
|
+
|
101
|
+
* ``pachner_search_tries``: Controls how hard to search for a
|
102
|
+
suitable sequence of Pachner moves from the filled input
|
103
|
+
triangulation to a standard triangulation of the 3-sphere.
|
104
|
+
|
105
|
+
* ``seed``: The algorithm involves many random choices, and hence
|
106
|
+
each run typically produces a different diagram of the
|
107
|
+
underlying link. If you need the same output each time, you can
|
108
|
+
specify a fixed seed for the various pseudo-random number
|
109
|
+
generators.
|
110
|
+
|
111
|
+
Note on rigor: Provided at least one of ``check_answer`` and
|
112
|
+
``careful_perturbation`` is ``True``, the exterior of the output
|
113
|
+
link is guaranteed to match the input (including the choice of
|
114
|
+
meridians).
|
115
|
+
|
116
|
+
**Warning:** The order of the link components and the cusps of the
|
117
|
+
input manifold is only guaranteed to match when
|
118
|
+
``check_answer=True``. Even then, the implicit orientation along
|
119
|
+
each component of the link may not be preserved.
|
120
|
+
"""
|
121
|
+
|
122
|
+
unfilled = set(manifold.cusp_info('is_complete'))
|
123
|
+
if unfilled == {True, False}:
|
124
|
+
raise ValueError('Cusps should either be all filled or all unfilled')
|
125
|
+
|
126
|
+
if check_input and not filled_is_3sphere(manifold):
|
127
|
+
raise ValueError('Filling in the meridians does not obviously give S^3')
|
128
|
+
|
129
|
+
def print_status(*args, **kwargs):
|
130
|
+
if verbose:
|
131
|
+
print(*args, **kwargs, flush=True)
|
132
|
+
|
133
|
+
print_status(f'Finding link for {manifold.name()}')
|
134
|
+
if seed is not None:
|
135
|
+
seed = int(seed)
|
136
|
+
random.seed(seed)
|
137
|
+
set_rand_seed(seed)
|
138
|
+
print_status(' Seed:', seed)
|
139
|
+
|
140
|
+
print_status(' Finding moves to base triangulation of S^3...')
|
141
|
+
tris_with_moves = good_simplification(manifold,
|
142
|
+
max_tries=pachner_search_tries)
|
143
|
+
if tris_with_moves:
|
144
|
+
M, moves, expanded_moves = tris_with_moves
|
145
|
+
else:
|
146
|
+
raise ExteriorToLinkError('Could not simplify to standard triangulation of S^3')
|
147
|
+
|
148
|
+
print_status(f' Starting with {len(M)} tets, to do {len(moves)} simple Pachner moves.')
|
149
|
+
M.perform_moves(moves, push=True, straighten=True, round=True, careful=careful_perturbation)
|
150
|
+
M.rebuild()
|
151
|
+
M.connect_arcs()
|
152
|
+
print_status(' Moves resulted in', sum(len(tet.arcs) for tet in M),
|
153
|
+
f'PL segments; max denom of coor is {M._curr_max_denom()}.')
|
154
|
+
print_status(' Embedding in S3...', end='')
|
155
|
+
link_in_R3 = put_in_S3.embed_link_in_S3(M)
|
156
|
+
link_in_R3 = link_projection.straighten_link(link_in_R3)
|
157
|
+
num_seg = sum(len(component) + 1 for component in link_in_R3)
|
158
|
+
print_status('got PL link of', num_seg ,'segments.')
|
159
|
+
print_status(' Projecting...', end='')
|
160
|
+
|
161
|
+
L = link_projection.project_to_diagram(link_in_R3)
|
162
|
+
if L is None:
|
163
|
+
raise ExteriorToLinkError('Was unable to project link')
|
164
|
+
|
165
|
+
L.simplify('basic')
|
166
|
+
print_status(f'got diagram with {len(L.crossings)} crossings.')
|
167
|
+
|
168
|
+
if simplify_link:
|
169
|
+
print_status(' Simplifying diagram...', end='')
|
170
|
+
L.simplify('pickup')
|
171
|
+
print_status(f'{len(L.crossings)} crossings...', end='')
|
172
|
+
L.simplify('global')
|
173
|
+
print_status(f'{len(L.crossings)} crossings.')
|
174
|
+
|
175
|
+
if check_answer:
|
176
|
+
E = L.exterior()
|
177
|
+
if unfilled == {True}:
|
178
|
+
F = manifold
|
179
|
+
else:
|
180
|
+
F = manifold.copy()
|
181
|
+
F.dehn_fill(F.num_cusps()*[(0, 0)])
|
182
|
+
F.randomize()
|
183
|
+
if hasattr(F, 'with_hyperbolic_structure'):
|
184
|
+
F = F.with_hyperbolic_structure()
|
185
|
+
|
186
|
+
iso = hyp_utils.orientation_preserving_link_isometries(E, F, tries=1000)
|
187
|
+
if iso is not None:
|
188
|
+
L = hyp_utils.reorder_link_components(L, iso.cusp_images())
|
189
|
+
E = L.exterior()
|
190
|
+
if hyp_utils.are_orient_pres_isometric_as_ordered_links(E, F):
|
191
|
+
print_status(' Exterior of final link checks!\n')
|
192
|
+
else:
|
193
|
+
ExteriorToLinkError('Could not correctly order link components')
|
194
|
+
else:
|
195
|
+
raise ExteriorToLinkError('Could not confirm topology of link exterior')
|
196
|
+
|
197
|
+
return L
|