snappy 3.3__cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snappy/CyOpenGL.cpython-310-aarch64-linux-gnu.so +0 -0
- snappy/SnapPy.cpython-310-aarch64-linux-gnu.so +0 -0
- snappy/SnapPy.ico +0 -0
- snappy/SnapPy.png +0 -0
- snappy/SnapPyHP.cpython-310-aarch64-linux-gnu.so +0 -0
- snappy/__init__.py +534 -0
- snappy/app.py +604 -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 +280 -0
- snappy/cusps/cusp_area_matrix.py +98 -0
- snappy/cusps/cusp_areas_from_matrix.py +96 -0
- snappy/cusps/maximal_cusp_area_matrix.py +136 -0
- snappy/cusps/short_slopes_for_cusp.py +217 -0
- snappy/cusps/test.py +22 -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 +717 -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/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 +52 -0
- snappy/doc/_sources/credits.rst.txt +81 -0
- snappy/doc/_sources/development.rst.txt +261 -0
- snappy/doc/_sources/index.rst.txt +215 -0
- snappy/doc/_sources/installing.rst.txt +249 -0
- snappy/doc/_sources/manifold.rst.txt +6 -0
- snappy/doc/_sources/manifoldhp.rst.txt +46 -0
- snappy/doc/_sources/news.rst.txt +425 -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 +906 -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 +149 -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 +192 -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 +635 -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 +453 -0
- snappy/doc/credits.html +184 -0
- snappy/doc/development.html +385 -0
- snappy/doc/doc-latest/additional_classes.html +1500 -0
- snappy/doc/doc-latest/bugs.html +132 -0
- snappy/doc/doc-latest/censuses.html +453 -0
- snappy/doc/doc-latest/credits.html +184 -0
- snappy/doc/doc-latest/development.html +385 -0
- snappy/doc/doc-latest/genindex.html +1349 -0
- snappy/doc/doc-latest/index.html +287 -0
- snappy/doc/doc-latest/installing.html +346 -0
- snappy/doc/doc-latest/manifold.html +3632 -0
- snappy/doc/doc-latest/manifoldhp.html +180 -0
- snappy/doc/doc-latest/news.html +438 -0
- snappy/doc/doc-latest/objects.inv +0 -0
- snappy/doc/doc-latest/other.html +160 -0
- snappy/doc/doc-latest/platonic_census.html +376 -0
- snappy/doc/doc-latest/plink.html +210 -0
- snappy/doc/doc-latest/ptolemy.html +253 -0
- snappy/doc/doc-latest/ptolemy_classes.html +1144 -0
- snappy/doc/doc-latest/ptolemy_examples1.html +409 -0
- snappy/doc/doc-latest/ptolemy_examples2.html +471 -0
- snappy/doc/doc-latest/ptolemy_examples3.html +414 -0
- snappy/doc/doc-latest/ptolemy_examples4.html +195 -0
- snappy/doc/doc-latest/ptolemy_prelim.html +248 -0
- snappy/doc/doc-latest/py-modindex.html +165 -0
- snappy/doc/doc-latest/screenshots.html +141 -0
- snappy/doc/doc-latest/search.html +135 -0
- snappy/doc/doc-latest/searchindex.js +1 -0
- snappy/doc/doc-latest/snap.html +202 -0
- snappy/doc/doc-latest/snappy.html +181 -0
- snappy/doc/doc-latest/spherogram.html +1346 -0
- snappy/doc/doc-latest/todo.html +166 -0
- snappy/doc/doc-latest/triangulation.html +1676 -0
- snappy/doc/doc-latest/tutorial.html +159 -0
- snappy/doc/doc-latest/verify.html +330 -0
- snappy/doc/doc-latest/verify_internals.html +1235 -0
- snappy/doc/genindex.html +1349 -0
- snappy/doc/index.html +287 -0
- snappy/doc/installing.html +346 -0
- snappy/doc/manifold.html +3632 -0
- snappy/doc/manifoldhp.html +180 -0
- snappy/doc/news.html +438 -0
- snappy/doc/objects.inv +0 -0
- snappy/doc/other.html +160 -0
- snappy/doc/platonic_census.html +376 -0
- snappy/doc/plink.html +210 -0
- snappy/doc/ptolemy.html +253 -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 +1346 -0
- snappy/doc/todo.html +166 -0
- snappy/doc/triangulation.html +1676 -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 +132 -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 +198 -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 +130 -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 +691 -0
- snappy/geometric_structure/cusp_neighborhood/cusp_cross_section_base.py +480 -0
- snappy/geometric_structure/cusp_neighborhood/exceptions.py +41 -0
- snappy/geometric_structure/cusp_neighborhood/real_cusp_cross_section.py +294 -0
- snappy/geometric_structure/cusp_neighborhood/tiles_for_cusp_neighborhood.py +156 -0
- snappy/geometric_structure/cusp_neighborhood/vertices.py +35 -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_representatives.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 +106 -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 +128 -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 +259 -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 +389 -0
- snappy/len_spec/__init__.py +609 -0
- snappy/len_spec/geodesic_info.py +129 -0
- snappy/len_spec/geodesic_key_info_dict.py +116 -0
- snappy/len_spec/geodesic_piece.py +146 -0
- snappy/len_spec/geometric_structure.py +182 -0
- snappy/len_spec/geometry.py +136 -0
- snappy/len_spec/length_spectrum_geodesic_info.py +185 -0
- snappy/len_spec/spine.py +128 -0
- snappy/len_spec/test.py +24 -0
- snappy/len_spec/test_cases.py +69 -0
- snappy/len_spec/tile.py +276 -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/margulis/__init__.py +332 -0
- snappy/margulis/cusp_neighborhood_neighborhood.py +66 -0
- snappy/margulis/geodesic_neighborhood.py +152 -0
- snappy/margulis/margulis_info.py +21 -0
- snappy/margulis/mu_from_neighborhood_pair.py +175 -0
- snappy/margulis/neighborhood.py +29 -0
- snappy/margulis/test.py +22 -0
- snappy/math_basics.py +187 -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 +856 -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 +995 -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 +124 -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 +119 -0
- snappy/settings.py +407 -0
- snappy/shell.py +53 -0
- snappy/snap/__init__.py +117 -0
- snappy/snap/character_varieties.py +375 -0
- snappy/snap/find_field.py +372 -0
- snappy/snap/fox_milnor.py +271 -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 +716 -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/__init__.py +194 -0
- snappy/snap/slice_obs_HKL/basics.py +236 -0
- snappy/snap/slice_obs_HKL/direct.py +217 -0
- snappy/snap/slice_obs_HKL/poly_norm.py +212 -0
- snappy/snap/slice_obs_HKL/rep_theory.py +424 -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 +139 -0
- snappy/snap/utilities.py +288 -0
- snappy/test.py +213 -0
- snappy/test_cases.py +263 -0
- snappy/testing.py +131 -0
- snappy/tiling/__init__.py +2 -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/quotient_dict.py +70 -0
- snappy/tiling/real_hash_dict.py +164 -0
- snappy/tiling/test.py +23 -0
- snappy/tiling/tile.py +224 -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-aarch64-linux-gnu.so +0 -0
- snappy/upper_halfspace/__init__.py +146 -0
- snappy/upper_halfspace/ideal_point.py +29 -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/real_algebra.py +286 -0
- snappy/verify/shapes.py +25 -0
- snappy/verify/square_extensions.py +1005 -0
- snappy/verify/test.py +72 -0
- snappy/verify/volume.py +128 -0
- snappy/version.py +2 -0
- snappy-3.3.dist-info/METADATA +58 -0
- snappy-3.3.dist-info/RECORD +541 -0
- snappy-3.3.dist-info/WHEEL +6 -0
- snappy-3.3.dist-info/entry_points.txt +2 -0
- snappy-3.3.dist-info/top_level.txt +28 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# t3m - software for studying triangulated 3-manifolds
|
|
2
|
+
# Copyright (C) 2002 Marc Culler, Nathan Dunfield and others
|
|
3
|
+
#
|
|
4
|
+
# This program is distributed under the terms of the
|
|
5
|
+
# GNU General Public License, version 2 or later, as published by
|
|
6
|
+
# the Free Software Foundation. See the file GPL.txt for details.
|
|
7
|
+
|
|
8
|
+
from .simplex import *
|
|
9
|
+
from .tetrahedron import Tetrahedron
|
|
10
|
+
# from numpy import dot, not_equal, zeros, compress
|
|
11
|
+
# from numpy.linalg import pinv as generalized_inverse
|
|
12
|
+
import sys
|
|
13
|
+
from .linalg import Vector, Matrix
|
|
14
|
+
|
|
15
|
+
# NOTE (1) The functions in this module only make sense for closed
|
|
16
|
+
# manifolds. It will need to be rewritten to accommodate spun normal
|
|
17
|
+
# surfaces. In particular, build_weights tries to compute the
|
|
18
|
+
# triangle weights from the quad weights. We could set them to
|
|
19
|
+
# infinity, I suppose, near a torus cusp.
|
|
20
|
+
#
|
|
21
|
+
# For spun surfaces we will want to compute the boundary slope. We
|
|
22
|
+
# should perhaps decide what the degenerate form of the boundary slope
|
|
23
|
+
# is for a spherical vertex link. (0/0?) For a higher genus vertex
|
|
24
|
+
# link the object that corresponds to a boundary slope is an element
|
|
25
|
+
# of H^1 of the link. This is the class represented by the shift
|
|
26
|
+
# cocycle. The boundary class generates the kernel of the shift
|
|
27
|
+
# class, in the genus 1 case. Now that I mention it, I think that
|
|
28
|
+
# the shift class is the natural object to compute in all cases.
|
|
29
|
+
#
|
|
30
|
+
# NOTE (2) Many of the functions in this module also assume that the
|
|
31
|
+
# triangulation has only one vertex. If there are more vertices then one
|
|
32
|
+
# has to be more careful about saying things like "bounds a thick subcomplex"
|
|
33
|
+
# or "bounds a thin subcomplex" - it might bound both. And an edge linkig
|
|
34
|
+
# surface might not be a torus. It might be good to distinguish surfaces
|
|
35
|
+
# that bound regular neighborhoods of graphs from other surfaces that bound
|
|
36
|
+
# thin subcomplexes.
|
|
37
|
+
#
|
|
38
|
+
# NOTE (3) Our plan is to create (at least) three subclasses of the
|
|
39
|
+
# Surface class: Closed_Surface, Spun_Surface, Bounded_Surface.
|
|
40
|
+
|
|
41
|
+
# Incidence dictionaries for quads, triangles and octagons
|
|
42
|
+
|
|
43
|
+
MeetsQuad = {E01:Vector((1,1,0)), E02:Vector((1,0,1)), E21:Vector((0,1,1)),
|
|
44
|
+
E32:Vector((1,1,0)), E31:Vector((1,0,1)), E03:Vector((0,1,1))}
|
|
45
|
+
|
|
46
|
+
MeetsTri = {E01:Vector((1,1,0,0)), E02:Vector((1,0,1,0)), E21:Vector((0,1,1,0)),
|
|
47
|
+
E32:Vector((0,0,1,1)), E31:Vector((0,1,0,1)), E03:Vector((1,0,0,1))}
|
|
48
|
+
|
|
49
|
+
MeetsOct = {E01:Vector((1,1,2)), E02:Vector((1,2,1)), E21:Vector((2,1,1)),
|
|
50
|
+
E32:Vector((1,1,2)), E31:Vector((1,2,1)), E03:Vector((2,1,1))}
|
|
51
|
+
|
|
52
|
+
DisjointQuad = {E01:2, E02:1, E21:0,
|
|
53
|
+
E32:2, E31:1, E03:0}
|
|
54
|
+
|
|
55
|
+
QuadWeights = (Vector((1,0,0)), Vector((0,1,0)), Vector((0,0,1)) )
|
|
56
|
+
|
|
57
|
+
WeightVector = Vector([1,1,1])
|
|
58
|
+
|
|
59
|
+
TypeVector = Vector([0,1,2])
|
|
60
|
+
|
|
61
|
+
# Used for converting normal surface into tetrahedron edge-shift data.
|
|
62
|
+
# QuadShift[k] is the shifts induced by quad Qk3 along edges (E03, E13, E23).
|
|
63
|
+
# Note that this follows the convention that the order of the edges
|
|
64
|
+
# is the same as the order of the quads, and _not_ in order E01, E02, E03.
|
|
65
|
+
|
|
66
|
+
QuadShifts = ((0, 1, -1), (-1, 0, 1), (1, -1, 0))
|
|
67
|
+
|
|
68
|
+
# The format for a coefficient vector is [T0, T1, T2, T3, Q0, Q1, Q2, ...}
|
|
69
|
+
|
|
70
|
+
NonInteger = 'Error'
|
|
71
|
+
|
|
72
|
+
# NOTE: The convention is that the order of the quads is (Q03, Q13, Q23)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def gcd(x, y):
|
|
76
|
+
if x == 0:
|
|
77
|
+
if y == 0:
|
|
78
|
+
raise ValueError("gcd(0,0) is undefined.")
|
|
79
|
+
else:
|
|
80
|
+
return abs(y)
|
|
81
|
+
x = abs(x)
|
|
82
|
+
y = abs(y)
|
|
83
|
+
while y != 0:
|
|
84
|
+
r = x % y
|
|
85
|
+
x = y
|
|
86
|
+
y = r
|
|
87
|
+
return x
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def reduce_slope( slope ):
|
|
91
|
+
a, b = slope
|
|
92
|
+
if a == b == 0:
|
|
93
|
+
return slope, 0
|
|
94
|
+
g = gcd(a,b)
|
|
95
|
+
a, b = a/g, b/g
|
|
96
|
+
return (a,b), g
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Surface:
|
|
100
|
+
|
|
101
|
+
def __init__(self, manifold, quadvector):
|
|
102
|
+
self.Size = len(manifold)
|
|
103
|
+
Q = Matrix(self.Size, 3, [min(x, 1) for x in quadvector])
|
|
104
|
+
A = Matrix(self.Size, 3, quadvector)
|
|
105
|
+
self.Quadvector = quadvector
|
|
106
|
+
self.Coefficients = A.dot(WeightVector)
|
|
107
|
+
self.Quadtypes = Q.dot(TypeVector)
|
|
108
|
+
|
|
109
|
+
def type(self):
|
|
110
|
+
if min(self.Coefficients) < 0:
|
|
111
|
+
return "almost-normal"
|
|
112
|
+
else:
|
|
113
|
+
return "normal"
|
|
114
|
+
|
|
115
|
+
# computes and records hexagon shift of surface along
|
|
116
|
+
# the edges of each tet. Order convention of edges in
|
|
117
|
+
# each tet is (E03, E13, E23) the same as the standard
|
|
118
|
+
# order of the quads, and _not_ (E01, E02, E03).
|
|
119
|
+
|
|
120
|
+
def add_shifts(self):
|
|
121
|
+
shifts = []
|
|
122
|
+
for i in range(self.Size):
|
|
123
|
+
shifts += [ self.Coefficients[i] * w for w in QuadShifts[self.Quadtypes[i]]]
|
|
124
|
+
self.Shifts = shifts
|
|
125
|
+
|
|
126
|
+
def find_edge_linking_annuli(self, manifold):
|
|
127
|
+
"""
|
|
128
|
+
Surface.find_edge_linking_annuli(mcomplex) returns a list of the
|
|
129
|
+
indices of those edges for which the Surface contains an edge-linking
|
|
130
|
+
annulus (and hence has an obvious compression).
|
|
131
|
+
"""
|
|
132
|
+
if self not in manifold.NormalSurfaces:
|
|
133
|
+
raise ValueError('That manifold does not contain the Surface!')
|
|
134
|
+
linked_edges = []
|
|
135
|
+
for edge in manifold.Edges:
|
|
136
|
+
is_linked = 1
|
|
137
|
+
for corner in edge.Corners:
|
|
138
|
+
quad = DisjointQuad[corner.Subsimplex]
|
|
139
|
+
if ( self.Coefficients[corner.Tetrahedron.Index] == 0 or
|
|
140
|
+
self.Quadtypes[corner.Tetrahedron.Index] != quad ):
|
|
141
|
+
is_linked = 0
|
|
142
|
+
break
|
|
143
|
+
if is_linked:
|
|
144
|
+
linked_edges.append(edge.Index)
|
|
145
|
+
return linked_edges
|
|
146
|
+
|
|
147
|
+
def info(self, out=sys.stdout):
|
|
148
|
+
if self.type() == "normal":
|
|
149
|
+
out.write("Normal surface\n")
|
|
150
|
+
for i in range(self.Size):
|
|
151
|
+
quad_weight = self.Coefficients[i]
|
|
152
|
+
if quad_weight == -1:
|
|
153
|
+
weight = " Quad Type Q%d3, weight: octagon" % self.Quadtypes[i]
|
|
154
|
+
elif quad_weight > 0:
|
|
155
|
+
weight = " Quad Type Q%d3, weight %d" % (self.Quadtypes[i], quad_weight)
|
|
156
|
+
else:
|
|
157
|
+
weight = "No quads"
|
|
158
|
+
out.write(weight + "\n")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class ClosedSurface(Surface):
|
|
162
|
+
|
|
163
|
+
def __init__(self, manifold, quadvector):
|
|
164
|
+
Surface.__init__(self, manifold, quadvector)
|
|
165
|
+
self.build_weights(manifold)
|
|
166
|
+
self.build_bounding_info(manifold)
|
|
167
|
+
self.find_euler_characteristic(manifold)
|
|
168
|
+
|
|
169
|
+
def build_weights(self, manifold):
|
|
170
|
+
"""
|
|
171
|
+
Use self.QuadWeights self.QuadTypes vector to construct
|
|
172
|
+
self.Weights and self.EdgeWeights. The vector self.Weights has size
|
|
173
|
+
7T and gives the weights of triangles and quads in each 3-simplex.
|
|
174
|
+
In each bank of 7 weights, the first 4 are triangle weights and the
|
|
175
|
+
last 3 are quad weights.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
# Here is how it works. We use the system of normal surface
|
|
179
|
+
# equations defined as follows. For each edge e, and each face f
|
|
180
|
+
# containing e, let t1 and t2 be the two tetrahedra containing f.
|
|
181
|
+
# The weight of e can be expressed as the sum of two quad weights
|
|
182
|
+
# and two triangle weights in each of t1 and t2. Set these
|
|
183
|
+
# expressions equal to get one equation in the system. The
|
|
184
|
+
# resulting system can be written as Aw = Bq where w is the
|
|
185
|
+
# (unknown) vector of triangle weights and q is the (known) vector
|
|
186
|
+
# of quad weights. Note that this system does not have positive
|
|
187
|
+
# coefficients, and the matrix A is singular with null space
|
|
188
|
+
# spanned by the triangle weights of the vertex links, which of
|
|
189
|
+
# course have all quad weights equal to 0. We can make the system
|
|
190
|
+
# non-singular by restricting to the orthogonal complement of the
|
|
191
|
+
# null space, i.e. by adding an equation for each vertex v which
|
|
192
|
+
# sets the sum of the coefficients of triangles in the support of
|
|
193
|
+
# Link(v) equal to 0. The resulting system A'w = b is now
|
|
194
|
+
# non-singular, but not square. We solve it by using the
|
|
195
|
+
# "generalized inverse". We then adjust the solution vector by
|
|
196
|
+
# adding the unique linear combination of vertex links which
|
|
197
|
+
# produces a non-negative vector w' with a coefficient of 0 on
|
|
198
|
+
# some triangle in each vertex links. Now we can construct
|
|
199
|
+
# self.Weights by interleaving the vector w' and the vector q of
|
|
200
|
+
# quadweights. The vector self.EdgeWeights is constructed by
|
|
201
|
+
# simply multiplying the incidence matrix for edges meeting quads
|
|
202
|
+
# and triangles times the vector self.Weights.
|
|
203
|
+
|
|
204
|
+
self.Weights = Vector( 7*self.Size )
|
|
205
|
+
eqns = []
|
|
206
|
+
constants = []
|
|
207
|
+
edge_matrix = []
|
|
208
|
+
for edge in manifold.Edges:
|
|
209
|
+
|
|
210
|
+
# Build the row of the incidence matrix that records which quads
|
|
211
|
+
# and triangles meet this edge. We can use any tetrahedron that
|
|
212
|
+
# meets this edge to compute the row.
|
|
213
|
+
|
|
214
|
+
edge_row = Vector( 7*len(manifold) )
|
|
215
|
+
corner = edge.Corners[0]
|
|
216
|
+
j = corner.Tetrahedron.Index
|
|
217
|
+
edge_row[7*j:7*j+4] = MeetsTri[corner.Subsimplex]
|
|
218
|
+
if not self.Coefficients[j] == -1:
|
|
219
|
+
edge_row[7*j+4:7*j+7] = MeetsQuad[corner.Subsimplex]
|
|
220
|
+
else:
|
|
221
|
+
edge_row[7*j+4:7*j+7] = MeetsOct[corner.Subsimplex]
|
|
222
|
+
edge_matrix.append(edge_row)
|
|
223
|
+
|
|
224
|
+
# Build a row of A and a coefficient of the right hand side for
|
|
225
|
+
# each pair of adjacent 3-simplices that meet this edge.
|
|
226
|
+
for i in range(len(edge.Corners) - 1):
|
|
227
|
+
j = edge.Corners[i].Tetrahedron.Index
|
|
228
|
+
k = edge.Corners[i+1].Tetrahedron.Index
|
|
229
|
+
row = Vector(4*len(manifold))
|
|
230
|
+
row[4*j:4*j+4] = MeetsTri[edge.Corners[i].Subsimplex]
|
|
231
|
+
row[4*k:4*k+4] -= MeetsTri[edge.Corners[i+1].Subsimplex]
|
|
232
|
+
eqns.append(row)
|
|
233
|
+
c = 0
|
|
234
|
+
if self.Coefficients[k] == -1:
|
|
235
|
+
c = MeetsOct[edge.Corners[i+1].Subsimplex][self.Quadtypes[k]]
|
|
236
|
+
else:
|
|
237
|
+
if MeetsQuad[edge.Corners[i+1].Subsimplex][self.Quadtypes[k]]:
|
|
238
|
+
c = self.Coefficients[k]
|
|
239
|
+
if self.Coefficients[j] == -1:
|
|
240
|
+
c -= MeetsOct[edge.Corners[i].Subsimplex][self.Quadtypes[j]]
|
|
241
|
+
else:
|
|
242
|
+
if MeetsQuad[edge.Corners[i].Subsimplex][self.Quadtypes[j]]:
|
|
243
|
+
c -= self.Coefficients[j]
|
|
244
|
+
constants.append(c)
|
|
245
|
+
# Now add the extra equations to kill off the vertex links.
|
|
246
|
+
for vertex in manifold.Vertices:
|
|
247
|
+
eqns.append(vertex.IncidenceVector)
|
|
248
|
+
constants.append(0)
|
|
249
|
+
|
|
250
|
+
A = Matrix(eqns)
|
|
251
|
+
b = Vector(constants)
|
|
252
|
+
x = A.solve(b)
|
|
253
|
+
# Subtract off as many vertex links as possible.
|
|
254
|
+
for vertex in manifold.Vertices:
|
|
255
|
+
vert_vec = vertex.IncidenceVector
|
|
256
|
+
m = min([x[i] for i, w in enumerate(vert_vec) if w])
|
|
257
|
+
x -= Vector(m*vert_vec)
|
|
258
|
+
|
|
259
|
+
for i in range(len(manifold)):
|
|
260
|
+
for j in range(4):
|
|
261
|
+
v = x[4*i+j]
|
|
262
|
+
assert int(v) == v
|
|
263
|
+
self.Weights[7*i + j ] = int(v)
|
|
264
|
+
if not self.Coefficients[i] == -1:
|
|
265
|
+
self.Weights[7*i + 4: 7*i + 7] = (
|
|
266
|
+
self.Coefficients[i]*QuadWeights[int(self.Quadtypes[i])] )
|
|
267
|
+
else:
|
|
268
|
+
self.Weights[7*i + 4: 7*i + 7] = QuadWeights[int(self.Quadtypes[i])]
|
|
269
|
+
|
|
270
|
+
self.EdgeWeights = Matrix(edge_matrix).dot(self.Weights)
|
|
271
|
+
|
|
272
|
+
def find_euler_characteristic(self, manifold):
|
|
273
|
+
# An EdgeValence is the number of tetrahedra that meet the edge.
|
|
274
|
+
# The number of 2-simplices that meet the edge is larger by 1 in
|
|
275
|
+
# the case of a boundary edge.
|
|
276
|
+
valences = Vector(manifold.EdgeValences)
|
|
277
|
+
for edge in manifold.Edges:
|
|
278
|
+
if edge.IntOrBdry == 'bdry':
|
|
279
|
+
valences[edge.Index] += 1
|
|
280
|
+
V = sum(self.EdgeWeights)
|
|
281
|
+
E = (self.EdgeWeights*valences)/2
|
|
282
|
+
F = sum(abs(self.Weights))
|
|
283
|
+
self.EulerCharacteristic = V - E + F
|
|
284
|
+
|
|
285
|
+
# takes either a triangle given as the corresponding vertex
|
|
286
|
+
# or a quad given as an edge disjoint from it.
|
|
287
|
+
|
|
288
|
+
def get_weight(self, tet_number, subsimplex):
|
|
289
|
+
D = {V0: 0, V1:1, V2:2, V3:3, E03:4, E12:4, E13:5, E02:5, E23:6, E01:6}
|
|
290
|
+
return self.Weights[7*tet_number + D[subsimplex] ]
|
|
291
|
+
|
|
292
|
+
def has_quad(self, tet_number):
|
|
293
|
+
return max([self.get_weight(tet_number, e) for e in [E01, E02, E03]]) > 0
|
|
294
|
+
|
|
295
|
+
def get_edge_weight(self, edge):
|
|
296
|
+
j = edge.Index
|
|
297
|
+
return self.EdgeWeights[j]
|
|
298
|
+
|
|
299
|
+
# The next function decides if a normal surface bounds a subcomplex.
|
|
300
|
+
# The thing is to note is that given any surface, then there is a unique
|
|
301
|
+
# maximal subcomplex disjoint from it -- consisting of all simplices
|
|
302
|
+
# of any dimension disjoint from it. (For a normal surface, the boundary
|
|
303
|
+
# of a regular nbhd of this subcomplex is always normal.) It's not
|
|
304
|
+
# hard to see that a normal surface bounds a subcomplex iff all edge weights
|
|
305
|
+
# are 0 or 2. The function build_bounding_info sets self.BoundingInfo to:
|
|
306
|
+
#
|
|
307
|
+
# (bounds subcomplex, double bounds subcomplex, thick_or_thin)
|
|
308
|
+
#
|
|
309
|
+
# where thick_or_thin describes whether there is a tetrahedron contained
|
|
310
|
+
# in the subcomplex bounded by the surface or its double.
|
|
311
|
+
|
|
312
|
+
def build_bounding_info(self, manifold):
|
|
313
|
+
if self.type() != "normal":
|
|
314
|
+
return (0, 0, None)
|
|
315
|
+
|
|
316
|
+
bounds_subcomplex = 1
|
|
317
|
+
double_bounds_subcomplex = 1
|
|
318
|
+
for w in self.EdgeWeights:
|
|
319
|
+
if w != 0 and w != 2:
|
|
320
|
+
bounds_subcomplex = 0
|
|
321
|
+
if w != 0 and w != 1:
|
|
322
|
+
double_bounds_subcomplex = 0
|
|
323
|
+
if not (bounds_subcomplex or double_bounds_subcomplex):
|
|
324
|
+
break
|
|
325
|
+
|
|
326
|
+
if bounds_subcomplex or double_bounds_subcomplex:
|
|
327
|
+
thick_or_thin = "thin"
|
|
328
|
+
for tet in manifold.Tetrahedra:
|
|
329
|
+
inside = 1
|
|
330
|
+
for e in OneSubsimplices:
|
|
331
|
+
w = self.get_edge_weight(tet.Class[e])
|
|
332
|
+
if w != 0:
|
|
333
|
+
inside = 0
|
|
334
|
+
break
|
|
335
|
+
|
|
336
|
+
if inside:
|
|
337
|
+
thick_or_thin = "thick"
|
|
338
|
+
break
|
|
339
|
+
|
|
340
|
+
else:
|
|
341
|
+
thick_or_thin = None
|
|
342
|
+
|
|
343
|
+
self.BoundingInfo = (bounds_subcomplex, double_bounds_subcomplex, thick_or_thin)
|
|
344
|
+
|
|
345
|
+
# It is not a torus unless the edge is a loop!
|
|
346
|
+
# A surface is an edge linking torus iff all edge weights are 2 except one which
|
|
347
|
+
# is zero. Returns pair (is linking torus, edge it links around).
|
|
348
|
+
|
|
349
|
+
def is_edge_linking_torus(self):
|
|
350
|
+
zeroes = 0
|
|
351
|
+
zero_index = None
|
|
352
|
+
for i in range(len(self.EdgeWeights)):
|
|
353
|
+
w = self.EdgeWeights[i]
|
|
354
|
+
if w == 0:
|
|
355
|
+
if zeroes > 0:
|
|
356
|
+
return (0, None)
|
|
357
|
+
zeroes = 1
|
|
358
|
+
zero_index = i
|
|
359
|
+
elif w != 2:
|
|
360
|
+
return (0, None)
|
|
361
|
+
|
|
362
|
+
return (1, zero_index)
|
|
363
|
+
|
|
364
|
+
def info(self, manifold, out=sys.stdout):
|
|
365
|
+
if self.type() == "normal":
|
|
366
|
+
# check if really boring:
|
|
367
|
+
q, e = self.is_edge_linking_torus()
|
|
368
|
+
if q:
|
|
369
|
+
out.write("Normal surface #%d is thin linking torus of edge %s\n"
|
|
370
|
+
% (manifold.NormalSurfaces.index(self), manifold.Edges[e]))
|
|
371
|
+
return
|
|
372
|
+
out.write("Normal surface #%d of Euler characteristic %d\n"
|
|
373
|
+
% (manifold.NormalSurfaces.index(self), self.EulerCharacteristic))
|
|
374
|
+
# additional message about bounding subcomplex
|
|
375
|
+
b, d, t = self.BoundingInfo
|
|
376
|
+
if b == 1:
|
|
377
|
+
out.write(" Bounds %s subcomplex\n" % t)
|
|
378
|
+
elif d == 1:
|
|
379
|
+
out.write(" Double bounds %s subcomplex\n" % t)
|
|
380
|
+
else:
|
|
381
|
+
out.write(" doesn't bound subcomplex\n")
|
|
382
|
+
else:
|
|
383
|
+
out.write("Almost-normal surface #%d of Euler characteristic %d\n"
|
|
384
|
+
% (manifold.AlmostNormalSurfaces.index(self),
|
|
385
|
+
self.EulerCharacteristic))
|
|
386
|
+
out.write('\n')
|
|
387
|
+
for i in range(self.Size):
|
|
388
|
+
quad_weight = self.Coefficients[i]
|
|
389
|
+
if quad_weight == -1:
|
|
390
|
+
weight = " Quad Type Q%d3, weight: octagon" % self.Quadtypes[i]
|
|
391
|
+
elif quad_weight > 0:
|
|
392
|
+
weight = " Quad Type Q%d3, weight %d" % (self.Quadtypes[i], quad_weight)
|
|
393
|
+
else:
|
|
394
|
+
weight = "No quads"
|
|
395
|
+
out.write(" In tetrahedron %s : %s\n" %
|
|
396
|
+
(manifold.Tetrahedra[i], weight))
|
|
397
|
+
out.write("\tTri weights V0: %d V1: %d V2 : %d V3 : %d\n"
|
|
398
|
+
% (self.get_weight(i, V0),
|
|
399
|
+
self.get_weight(i, V1),
|
|
400
|
+
self.get_weight(i, V2),
|
|
401
|
+
self.get_weight(i, V3)))
|
|
402
|
+
out.write('\n')
|
|
403
|
+
|
|
404
|
+
for i in range(len(self.EdgeWeights)):
|
|
405
|
+
out.write(" Edge %s has weight %d\n"
|
|
406
|
+
% (manifold.Edges[i], self.EdgeWeights[i]))
|
|
407
|
+
|
|
408
|
+
def casson_split(self, manifold):
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
Returns the "Casson Split" of the manifold along the normal
|
|
412
|
+
surface. That is, splits the manifold open along the surface
|
|
413
|
+
and replaces the "combinatorial I-bundles" by I-bundles over
|
|
414
|
+
disks. Of course, doing so may change the topology of
|
|
415
|
+
complementary manifold.
|
|
416
|
+
|
|
417
|
+
"""
|
|
418
|
+
M = manifold
|
|
419
|
+
have_quads = [self.has_quad(i) for i in range(len(M))]
|
|
420
|
+
new_tets = {}
|
|
421
|
+
for i in have_quads:
|
|
422
|
+
new_tets[i] = Tetrahedron()
|
|
423
|
+
for i in have_quads:
|
|
424
|
+
T = new_tets[i]
|
|
425
|
+
|
|
426
|
+
# -----------------end class ClosedSurface---------------------------------------
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
# -----------------begin class SpunSurface--------------------------------------
|
|
430
|
+
|
|
431
|
+
def dot_product(x,y):
|
|
432
|
+
assert len(x) == len(y)
|
|
433
|
+
dot = 0
|
|
434
|
+
for i in range(len(x)):
|
|
435
|
+
dot += x[i]*y[i]
|
|
436
|
+
return dot
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
class SpunSurface(Surface):
|
|
440
|
+
|
|
441
|
+
def __init__(self, manifold, quadvector):
|
|
442
|
+
Surface.__init__(self, manifold, quadvector)
|
|
443
|
+
self.Incompressible = None
|
|
444
|
+
self.BoundarySlope = None
|
|
445
|
+
|
|
446
|
+
def add_boundary_slope(surface, cusp_equations):
|
|
447
|
+
surface.BoundarySlope = (-dot_product(surface.Shifts, cusp_equations[1]),
|
|
448
|
+
dot_product(surface.Shifts, cusp_equations[0]) )
|
|
449
|
+
|
|
450
|
+
def find_euler_characteristic(self, manifold):
|
|
451
|
+
quadvector = array(self.Quadvector, 'd')
|
|
452
|
+
floatresult = dot(manifold.Anglevector, quadvector)
|
|
453
|
+
intresult = round(floatresult)
|
|
454
|
+
error = abs(floatresult - intresult)
|
|
455
|
+
if error > .0000001:
|
|
456
|
+
raise OverflowError('Yikes! A non-integral euler characteristic!')
|
|
457
|
+
return -int(intresult)
|
|
458
|
+
|
|
459
|
+
def info(self, manifold, out=sys.stdout):
|
|
460
|
+
out.write("SpunSurface.\n Slope: %s; Boundary components: %d; " %
|
|
461
|
+
reduce_slope(self.BoundarySlope))
|
|
462
|
+
out.write("Euler characteristic: %d\n" %
|
|
463
|
+
self.find_euler_characteristic(manifold))
|
|
464
|
+
out.write(" Incompressible: %s\n" % self.Incompressible)
|
|
465
|
+
for i in range(self.Size):
|
|
466
|
+
quad_weight = self.Coefficients[i]
|
|
467
|
+
if quad_weight > 0:
|
|
468
|
+
weight = (" Tet %d: Quad Type Q%d3, weight %d" %
|
|
469
|
+
(i, self.Quadtypes[i], quad_weight))
|
|
470
|
+
else:
|
|
471
|
+
weight = " Tet %d: no quads" % i
|
|
472
|
+
out.write(weight + "\n")
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
# -------------begin class ClosedSurfaceInCusped------------------------
|
|
476
|
+
|
|
477
|
+
class ClosedSurfaceInCusped(ClosedSurface):
|
|
478
|
+
def __init__(self, manifold, quadvector):
|
|
479
|
+
ClosedSurface.__init__(self, manifold, quadvector)
|
|
480
|
+
self.Incompressible = None
|
|
481
|
+
self.BoundarySlope = None
|
|
482
|
+
|
|
483
|
+
def info(self, manifold, out=sys.stdout):
|
|
484
|
+
out.write("ClosedSurfaceInCusped #%d: Euler %d; Incompressible %s\n" %
|
|
485
|
+
(manifold.ClosedSurfaces.index(self), self.EulerCharacteristic, self.Incompressible))
|
|
486
|
+
# check if really boring:
|
|
487
|
+
q, e = self.is_edge_linking_torus()
|
|
488
|
+
if q:
|
|
489
|
+
out.write(" is thin linking surface of edge %s\n" % manifold.Edges[e])
|
|
490
|
+
return
|
|
491
|
+
|
|
492
|
+
# additional message about bounding subcomplex
|
|
493
|
+
b, d, t = self.BoundingInfo
|
|
494
|
+
if b == 1:
|
|
495
|
+
out.write(" Bounds %s subcomplex\n" % t)
|
|
496
|
+
elif d == 1:
|
|
497
|
+
out.write(" Double bounds %s subcomplex\n" % t)
|
|
498
|
+
else:
|
|
499
|
+
out.write(" Doesn't bound subcomplex\n")
|
|
500
|
+
|
|
501
|
+
for i in range(self.Size):
|
|
502
|
+
quad_weight = self.Coefficients[i]
|
|
503
|
+
if quad_weight > 0:
|
|
504
|
+
weight = " Quad Type Q%d3, weight %d" % (self.Quadtypes[i], quad_weight)
|
|
505
|
+
else:
|
|
506
|
+
weight = "No quads"
|
|
507
|
+
|
|
508
|
+
out.write(" In tet %s : %s\n" %
|
|
509
|
+
(manifold.Tetrahedra[i], weight))
|
|
510
|
+
out.write("\tTri weights V0: %d V1: %d V2 : %d V3 : %d\n"
|
|
511
|
+
% (self.get_weight(i, V0),
|
|
512
|
+
self.get_weight(i, V1),
|
|
513
|
+
self.get_weight(i, V2),
|
|
514
|
+
self.get_weight(i, V3)))
|
|
515
|
+
out.write('\n')
|
|
516
|
+
|
|
517
|
+
for i in range(len(self.EdgeWeights)):
|
|
518
|
+
out.write(" Edge %s has weight %d\n"
|
|
519
|
+
% (manifold.Edges[i], self.EdgeWeights[i]))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import snappy
|
|
2
|
+
import snappy.snap.t3mlite as t3m
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def closed_test():
|
|
6
|
+
for M in snappy.OrientableClosedCensus[:10]:
|
|
7
|
+
N = M.filled_triangulation()
|
|
8
|
+
T = t3m.Mcomplex(N)
|
|
9
|
+
T.find_normal_surfaces()
|
|
10
|
+
T.normal_surface_info()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def cusped_test():
|
|
14
|
+
for M in snappy.OrientableCuspedCensus[:10]:
|
|
15
|
+
T = t3m.Mcomplex(M)
|
|
16
|
+
T.find_normal_surfaces()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
closed_test()
|
|
20
|
+
cusped_test()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import snappy
|
|
2
|
+
import regina
|
|
3
|
+
import snappy.snap.t3mlite as t3m
|
|
4
|
+
import snappy.snap.t3mlite.spun as spun
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def hash_t3m_surface(surface):
|
|
8
|
+
ans = [surface.EulerCharacteristic]
|
|
9
|
+
ans += sorted(surface.EdgeWeights)
|
|
10
|
+
ans += sorted(surface.Quadvector)
|
|
11
|
+
return ans
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def hash_regina_surface(S):
|
|
15
|
+
T = S.getTriangulation()
|
|
16
|
+
t = T.getNumberOfTetrahedra()
|
|
17
|
+
ans = [S.getEulerCharacteristic()]
|
|
18
|
+
ans += sorted([S.getEdgeWeight(i) for i in range(T.getNumberOfEdges())])
|
|
19
|
+
ans += sorted([S.getQuadCoord(i, j) for i in range(t) for j in range(3)])
|
|
20
|
+
return ans
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def to_regina(snappy_manifold):
|
|
24
|
+
return regina.NTriangulation(snappy_manifold._to_string())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def vertex_surfaces(regina_triangulation):
|
|
28
|
+
"""
|
|
29
|
+
Enumerate the vertex surfaces of the given triangulation
|
|
30
|
+
in quad coordinates.
|
|
31
|
+
"""
|
|
32
|
+
surfaces = regina.NNormalSurfaceList.enumerate(
|
|
33
|
+
regina_triangulation, regina.NS_QUAD)
|
|
34
|
+
for i in range(surfaces.getNumberOfSurfaces()):
|
|
35
|
+
yield surfaces.getSurface(i)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def compare_closed(snappy_manifold):
|
|
39
|
+
N = snappy_manifold.filled_triangulation()
|
|
40
|
+
|
|
41
|
+
T = t3m.Mcomplex(N)
|
|
42
|
+
T.find_normal_surfaces()
|
|
43
|
+
t_hashes = sorted( hash_t3m_surface(S) for S in T.NormalSurfaces )
|
|
44
|
+
|
|
45
|
+
R = to_regina(N)
|
|
46
|
+
r_hashes = sorted( hash_regina_surface(S) for S in vertex_surfaces(R))
|
|
47
|
+
|
|
48
|
+
all_together = sum(t_hashes, [])
|
|
49
|
+
return t_hashes == r_hashes, len(all_together), sum(all_together)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def regina_boundary_slope(surface):
|
|
53
|
+
slope = surface.boundaryIntersections()
|
|
54
|
+
a = int(slope.entry(0,0).stringValue())
|
|
55
|
+
b = int(slope.entry(0,1).stringValue())
|
|
56
|
+
return (b, -a)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def compare_cusped(snappy_manifold):
|
|
60
|
+
tri_data = snappy_manifold._to_string()
|
|
61
|
+
T = spun.Manifold(tri_data)
|
|
62
|
+
t_hashes = sorted(sorted(S.quad_vector()) for S in T.normal_surfaces())
|
|
63
|
+
t_slopes = sorted(tuple(S.boundary_slopes()) for S in T.normal_surfaces())
|
|
64
|
+
|
|
65
|
+
R = regina.NSnapPeaTriangulation(tri_data)
|
|
66
|
+
t = R.getNumberOfTetrahedra()
|
|
67
|
+
regina_surfaces = list(vertex_surfaces(R))
|
|
68
|
+
r_hashes = sorted(
|
|
69
|
+
sorted(int(S.getQuadCoord(i, j).stringValue())
|
|
70
|
+
for i in range(t) for j in range(3))
|
|
71
|
+
for S in regina_surfaces)
|
|
72
|
+
r_slopes = sorted(map(regina_boundary_slope, regina_surfaces))
|
|
73
|
+
|
|
74
|
+
assert t_hashes == r_hashes and t_slopes == r_slopes
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def closed_test(N=10):
|
|
78
|
+
for M in snappy.OrientableClosedCensus[:N]:
|
|
79
|
+
print(M, compare_closed(M))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def cusped_test(N=100):
|
|
83
|
+
for census in [snappy.CensusKnots, snappy.OrientableCuspedCensus(cusps=1)]:
|
|
84
|
+
for M in census:
|
|
85
|
+
print(M)
|
|
86
|
+
compare_cusped(M)
|