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,372 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
|
|
3
|
+
from ..sage_helper import (cached_method, real_part, imag_part, round, ceil, floor, log,
|
|
4
|
+
ZZ, QQ, CDF, ComplexField, NumberField, PolynomialRing,
|
|
5
|
+
matrix, identity_matrix)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def error(poly, z, a=ZZ(0)):
|
|
9
|
+
"""
|
|
10
|
+
The number of bits above 2^-(precision of z)
|
|
11
|
+
for which
|
|
12
|
+
|
|
13
|
+
poly(z) = a
|
|
14
|
+
|
|
15
|
+
fails to hold.
|
|
16
|
+
"""
|
|
17
|
+
err = poly(z) - a
|
|
18
|
+
if err == 0:
|
|
19
|
+
return 0
|
|
20
|
+
return z.prec() + ceil(log(abs(poly(z) - a), 2))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def acceptable_error(poly, z, a, portion_bad):
|
|
24
|
+
"""
|
|
25
|
+
A error is judged as acceptable if poly(z) = a to within
|
|
26
|
+
2^-(portion_bad*z.prec())
|
|
27
|
+
"""
|
|
28
|
+
return error(poly, z, a) <= floor(portion_bad*z.prec())
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def best_algdep_factor(z, degree):
|
|
32
|
+
if hasattr(z, 'algebraic_dependency'): # Sage >= 8.0
|
|
33
|
+
return z.algebraic_dependency(degree)
|
|
34
|
+
else: # Sage < 8.0
|
|
35
|
+
P = z.algebraic_dependancy(degree)
|
|
36
|
+
return sorted( [p for p, e in P.factor()],
|
|
37
|
+
key=lambda p:abs(p(z)) )[0]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def complex_to_lattice(z, d, a, N=None):
|
|
41
|
+
"""
|
|
42
|
+
Given an algebraic number z of degree d, set of up the
|
|
43
|
+
lattice which tries to express a in terms of powers of z,
|
|
44
|
+
where the last two columns are weighted by N.
|
|
45
|
+
"""
|
|
46
|
+
if N is None:
|
|
47
|
+
N = ZZ(2)**(z.prec() - 10)
|
|
48
|
+
nums = [z**k for k in range(d)] + [a]
|
|
49
|
+
last_columns = [[round(N*real_part(x)) for x in nums], [round(N*imag_part(x)) for x in nums]]
|
|
50
|
+
A = matrix(identity_matrix(len(nums)).columns() + last_columns)
|
|
51
|
+
return A.transpose()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ApproximateAlgebraicNumber():
|
|
55
|
+
"""
|
|
56
|
+
An algebraic number which we can compute
|
|
57
|
+
to arbitrary precision. Specified by a function
|
|
58
|
+
where f(prec) is the number to 2^prec bits.
|
|
59
|
+
"""
|
|
60
|
+
def __init__(self, defining_function):
|
|
61
|
+
if defining_function in QQ:
|
|
62
|
+
x = QQ(defining_function)
|
|
63
|
+
defining_function = lambda prec: ComplexField(prec)(x)
|
|
64
|
+
self.f = defining_function
|
|
65
|
+
self._min_poly = None
|
|
66
|
+
|
|
67
|
+
def __repr__(self):
|
|
68
|
+
return '<ApproxAN: %s>' % CDF(self(100))
|
|
69
|
+
|
|
70
|
+
@cached_method
|
|
71
|
+
def __call__(self, prec):
|
|
72
|
+
return self.f(prec)
|
|
73
|
+
|
|
74
|
+
def min_polynomial(self, prec=100, degree=10):
|
|
75
|
+
if self._min_poly is None:
|
|
76
|
+
self_prec = self(prec)
|
|
77
|
+
p = best_algdep_factor(self_prec, degree)
|
|
78
|
+
z = self(2*prec)
|
|
79
|
+
if acceptable_error(p, z, ZZ(0), 0.2):
|
|
80
|
+
self._min_poly = p
|
|
81
|
+
self._default_precision = prec
|
|
82
|
+
self._approx_root = self_prec
|
|
83
|
+
|
|
84
|
+
return self._min_poly
|
|
85
|
+
|
|
86
|
+
def express(self, a, prec=None):
|
|
87
|
+
'Express the given number in terms of self'
|
|
88
|
+
if self._min_poly is None:
|
|
89
|
+
raise ValueError('Minimal polynomial is not known.')
|
|
90
|
+
if prec is None:
|
|
91
|
+
prec = self._default_precision
|
|
92
|
+
p = self._min_poly
|
|
93
|
+
z0, a0 = self(prec), a(prec)
|
|
94
|
+
A = complex_to_lattice(z0, p.degree(), a0)
|
|
95
|
+
v = A.LLL(delta=0.75)[0]
|
|
96
|
+
v = list(v)[:-2]
|
|
97
|
+
if v[-1] == 0:
|
|
98
|
+
return None
|
|
99
|
+
R = PolynomialRing(QQ, 'x')
|
|
100
|
+
q = -R(v[:-1])/v[-1]
|
|
101
|
+
|
|
102
|
+
# Now we double-check
|
|
103
|
+
z1, a1 = self(2*prec), a(2*prec)
|
|
104
|
+
if acceptable_error(q, z1, a1, 0.2):
|
|
105
|
+
return q
|
|
106
|
+
|
|
107
|
+
def express_several(self, elts, prec=None):
|
|
108
|
+
"""
|
|
109
|
+
Return exact expressions every number elts, provided this is
|
|
110
|
+
possible.
|
|
111
|
+
"""
|
|
112
|
+
ans = []
|
|
113
|
+
for a in elts:
|
|
114
|
+
exact = self.express(a, prec)
|
|
115
|
+
if exact is None:
|
|
116
|
+
return None
|
|
117
|
+
else:
|
|
118
|
+
ans.append(exact)
|
|
119
|
+
return ans
|
|
120
|
+
|
|
121
|
+
def can_express(self, a, prec=None):
|
|
122
|
+
return self.express(a, prec) is not None
|
|
123
|
+
|
|
124
|
+
def number_field(self):
|
|
125
|
+
p = self._min_poly
|
|
126
|
+
if p is None:
|
|
127
|
+
raise ValueError('Minimal polynomial is not known.')
|
|
128
|
+
q = p.change_ring(QQ)
|
|
129
|
+
q = (1/q.leading_coefficient())*q
|
|
130
|
+
return NumberField(q, 'z', embedding=self._approx_root)
|
|
131
|
+
|
|
132
|
+
def place(self, prec):
|
|
133
|
+
K = self.number_field()
|
|
134
|
+
z = self(prec)
|
|
135
|
+
CC = z.parent()
|
|
136
|
+
return K.hom(z, check=False, codomain=CC)
|
|
137
|
+
|
|
138
|
+
def __add__(self, other):
|
|
139
|
+
if not isinstance(other, ApproximateAlgebraicNumber):
|
|
140
|
+
raise ValueError
|
|
141
|
+
|
|
142
|
+
def f(prec):
|
|
143
|
+
return self(prec) + other(prec)
|
|
144
|
+
return ApproximateAlgebraicNumber(f)
|
|
145
|
+
|
|
146
|
+
def __mul__(self, other):
|
|
147
|
+
if not isinstance(other, ApproximateAlgebraicNumber):
|
|
148
|
+
raise ValueError
|
|
149
|
+
|
|
150
|
+
def f(prec):
|
|
151
|
+
return self(prec)*other(prec)
|
|
152
|
+
return ApproximateAlgebraicNumber(f)
|
|
153
|
+
|
|
154
|
+
def __div__(self, other):
|
|
155
|
+
if not isinstance(other, ApproximateAlgebraicNumber):
|
|
156
|
+
raise ValueError
|
|
157
|
+
|
|
158
|
+
def f(prec):
|
|
159
|
+
return self(prec)/other(prec)
|
|
160
|
+
return ApproximateAlgebraicNumber(f)
|
|
161
|
+
|
|
162
|
+
def __pow__(self, n):
|
|
163
|
+
def f(prec):
|
|
164
|
+
return self(prec)**n
|
|
165
|
+
return ApproximateAlgebraicNumber(f)
|
|
166
|
+
|
|
167
|
+
def __neg__(self):
|
|
168
|
+
def f(prec):
|
|
169
|
+
return -self(prec)
|
|
170
|
+
return ApproximateAlgebraicNumber(f)
|
|
171
|
+
|
|
172
|
+
def __sub__(self, other):
|
|
173
|
+
return self + other.__neg__()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class ExactAlgebraicNumber(ApproximateAlgebraicNumber):
|
|
177
|
+
"""
|
|
178
|
+
An ApproximateAlgebraicNumber which is specified
|
|
179
|
+
explicitly by its minimal polynomial.
|
|
180
|
+
"""
|
|
181
|
+
def __init__(self, poly, approx_root):
|
|
182
|
+
if not acceptable_error(poly, approx_root, ZZ(0), 0.2):
|
|
183
|
+
raise ValueError('Given number does not seem to be a root of this polynomial')
|
|
184
|
+
self._min_poly = poly
|
|
185
|
+
self._approx_root = approx_root
|
|
186
|
+
|
|
187
|
+
@cached_method
|
|
188
|
+
def __call__(self, prec):
|
|
189
|
+
roots = [r[0] for r in self._min_poly.roots(ComplexField(prec))]
|
|
190
|
+
|
|
191
|
+
def dist_to_defining_root(z):
|
|
192
|
+
return abs(z - self._approx_root)
|
|
193
|
+
return sorted(roots, key=dist_to_defining_root)[0]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def optimize_field_generator(z):
|
|
197
|
+
p = z.min_polynomial()
|
|
198
|
+
assert p.base_ring() == ZZ
|
|
199
|
+
a, n = p.leading_coefficient(), p.degree()
|
|
200
|
+
x = PolynomialRing(QQ, 'x').gen()
|
|
201
|
+
q = a**(n-1) * p(x/a)
|
|
202
|
+
root_of_q = a*z(1000)
|
|
203
|
+
K = NumberField(q, 'x')
|
|
204
|
+
F, F_to_K, K_to_F = K.optimized_representation()
|
|
205
|
+
w = F_to_K(F.gen()).polynomial()(root_of_q)
|
|
206
|
+
f = F.defining_polynomial()
|
|
207
|
+
f = f.denominator() * f
|
|
208
|
+
return ExactAlgebraicNumber(f.change_ring(ZZ), w)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class ListOfApproximateAlgebraicNumbers():
|
|
212
|
+
def __init__(self, defining_function):
|
|
213
|
+
self.f = defining_function
|
|
214
|
+
self.n = len(defining_function(100))
|
|
215
|
+
self._field = {True:None, False:None}
|
|
216
|
+
|
|
217
|
+
@cached_method
|
|
218
|
+
def __call__(self, prec):
|
|
219
|
+
return self.f(prec)
|
|
220
|
+
|
|
221
|
+
@cached_method
|
|
222
|
+
def __getitem__(self, index):
|
|
223
|
+
def f(n):
|
|
224
|
+
return self(n)[index]
|
|
225
|
+
return ApproximateAlgebraicNumber(f)
|
|
226
|
+
|
|
227
|
+
def list(self):
|
|
228
|
+
return [self[i] for i in range(self.n)]
|
|
229
|
+
|
|
230
|
+
def __repr__(self):
|
|
231
|
+
return '<SetOfAAN: %s>' % [CDF(z) for z in self.f(100)]
|
|
232
|
+
|
|
233
|
+
def __len__(self):
|
|
234
|
+
return self.n
|
|
235
|
+
|
|
236
|
+
def are_in_field_generated_by(self, z, prec=None):
|
|
237
|
+
ans = []
|
|
238
|
+
for i in range(self.n):
|
|
239
|
+
p = z.express(self[i], prec)
|
|
240
|
+
if p is None:
|
|
241
|
+
return None
|
|
242
|
+
ans.append(p)
|
|
243
|
+
return ans
|
|
244
|
+
|
|
245
|
+
def _find_field_uncached(self, prec, degree, verbosity=False):
|
|
246
|
+
# Works similar to snap's field::generated_by
|
|
247
|
+
#
|
|
248
|
+
# The input elts is a list of approximate algebraic numbers (i.e., high
|
|
249
|
+
# precisions of numbers known to be algebraic).
|
|
250
|
+
#
|
|
251
|
+
# We iteratively try to construct an approximate algebraic number z
|
|
252
|
+
# whose minimal polynomial can be computed such that all elements
|
|
253
|
+
# in the input considered up to that point are lying inside the field
|
|
254
|
+
# generated by z. z will be the sum over some subset of given elements.
|
|
255
|
+
#
|
|
256
|
+
# We return the number field (as sage number field) associated to
|
|
257
|
+
# z's minimal polynomial, the approximate value of z and exact
|
|
258
|
+
# expressions of all inputs as polynomials in the root of the
|
|
259
|
+
# minimal polynomial
|
|
260
|
+
#
|
|
261
|
+
# In each iteration, we check whether the newly considered element can
|
|
262
|
+
# be expressed as algebraic expression in z. If yes, we keep z and
|
|
263
|
+
# remember how the newly considered element can be expressed.
|
|
264
|
+
# If no, we consider the newly considered element itself and the sum
|
|
265
|
+
# of it and the old z as new candidate z.
|
|
266
|
+
|
|
267
|
+
# Helper functions
|
|
268
|
+
def min_poly(z):
|
|
269
|
+
return z.min_polynomial(prec, degree)
|
|
270
|
+
|
|
271
|
+
def min_poly_deg(z):
|
|
272
|
+
return z.min_polynomial().degree()
|
|
273
|
+
|
|
274
|
+
def message(*args):
|
|
275
|
+
if verbosity:
|
|
276
|
+
print(*args)
|
|
277
|
+
# assert False
|
|
278
|
+
|
|
279
|
+
# The input list
|
|
280
|
+
elts = self.list()
|
|
281
|
+
|
|
282
|
+
# Start with z = 1 in the number field Q
|
|
283
|
+
z = ApproximateAlgebraicNumber(1)
|
|
284
|
+
z.min_polynomial()
|
|
285
|
+
|
|
286
|
+
# The exact expressions for inputs
|
|
287
|
+
exact_elts = []
|
|
288
|
+
|
|
289
|
+
# Iterate
|
|
290
|
+
for i, elt in enumerate(elts):
|
|
291
|
+
# Can the newly considered element elt be expressed in the old z
|
|
292
|
+
exact_elt = z.express(elt, prec)
|
|
293
|
+
if exact_elt is not None:
|
|
294
|
+
# If yes, remember it as its exact representation
|
|
295
|
+
exact_elts.append(exact_elt)
|
|
296
|
+
else:
|
|
297
|
+
# If no, try to get a minimal polynomial for elt
|
|
298
|
+
if min_poly(elt) is None:
|
|
299
|
+
message("Bailing: no minimal polynomial found for "
|
|
300
|
+
"newly considered element", elt)
|
|
301
|
+
return None
|
|
302
|
+
|
|
303
|
+
# Search for a primitive element for the field generated by
|
|
304
|
+
# z and elt.
|
|
305
|
+
found = False
|
|
306
|
+
candidates = [elt, z + elt, z - elt, z*elt, elt + elt + z, z + z + elt,
|
|
307
|
+
elt + elt - z, z + z - elt, z + z*elt, elt + elt*z]
|
|
308
|
+
for w in candidates:
|
|
309
|
+
if min_poly(w) is None:
|
|
310
|
+
message("Skipping: no minimal polynomial found for "
|
|
311
|
+
"possible primitive element", elt)
|
|
312
|
+
else:
|
|
313
|
+
# If Q(w) contains both w and elt, then we've found
|
|
314
|
+
# the needed primitive element.
|
|
315
|
+
if (min_poly_deg(w) >= min_poly_deg(z)
|
|
316
|
+
and w.can_express(z, prec) and w.can_express(elt, prec)):
|
|
317
|
+
exact_elts = w.express_several(elts[:i+1], prec)
|
|
318
|
+
if exact_elts is None:
|
|
319
|
+
message("Bailing: Couldn't express everything"
|
|
320
|
+
"in terms of primitive element")
|
|
321
|
+
return None
|
|
322
|
+
found, z = True, w
|
|
323
|
+
break
|
|
324
|
+
|
|
325
|
+
if not found:
|
|
326
|
+
message("Bailing: Couldn't find primitive element for larger field")
|
|
327
|
+
return None
|
|
328
|
+
|
|
329
|
+
field = z.number_field()
|
|
330
|
+
exact_elts = [field(exact_elt) for exact_elt in exact_elts]
|
|
331
|
+
return field, z, exact_elts
|
|
332
|
+
|
|
333
|
+
def find_field(self, prec, degree, optimize=False, verbosity=False):
|
|
334
|
+
|
|
335
|
+
# Adding verbosity for now to debug potential problems
|
|
336
|
+
|
|
337
|
+
# We always need the unoptimized generator
|
|
338
|
+
if self._field[False] is None:
|
|
339
|
+
self._field[False] = self._find_field_uncached(prec, degree,
|
|
340
|
+
verbosity)
|
|
341
|
+
|
|
342
|
+
# If we need to optimize the generator
|
|
343
|
+
if optimize and self._field[True] is None:
|
|
344
|
+
if self._field[False] is None:
|
|
345
|
+
# Bail if no unoptimized generator
|
|
346
|
+
return None
|
|
347
|
+
|
|
348
|
+
K, z, exact_elts = self._field[False]
|
|
349
|
+
# Optimize generator
|
|
350
|
+
z = optimize_field_generator(z)
|
|
351
|
+
# Try to express elements in it
|
|
352
|
+
exact_elts = self.are_in_field_generated_by(z, prec)
|
|
353
|
+
if exact_elts is None:
|
|
354
|
+
if verbosity:
|
|
355
|
+
print("Bailing: Could not express elements in optimized "
|
|
356
|
+
"generator", z)
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
field = z.number_field()
|
|
360
|
+
exact_elts = [ field(exact_elt) for exact_elt in exact_elts ]
|
|
361
|
+
|
|
362
|
+
self._field[True] = (field, z, exact_elts)
|
|
363
|
+
|
|
364
|
+
return self._field[optimize]
|
|
365
|
+
|
|
366
|
+
def _as_exact_matrices(self, optimize=None):
|
|
367
|
+
if optimize is None:
|
|
368
|
+
optimize = self._field[True] is not None
|
|
369
|
+
if len(self) % 4:
|
|
370
|
+
raise ValueError("Not right number of values to form 2x2 matrices")
|
|
371
|
+
K, z, ans = self._field[optimize]
|
|
372
|
+
return z, [matrix(K, 2, 2, ans[n:n+4]) for n in range(0, len(ans), 4)]
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Implements the Fox-Milnor for test for Alexander polynomials which
|
|
3
|
+
gives an obstruction for a link being strongly slice.
|
|
4
|
+
|
|
5
|
+
Specifically, we is the basic Fox-Milnor test of Corollary 12.3.14 of
|
|
6
|
+
[Kawauchi, A survey of knot theory] and also Theorem 8.18 of
|
|
7
|
+
[Lickorish, Intro to knot theory].
|
|
8
|
+
|
|
9
|
+
The main function provided is `fox_milnor_test`.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from ..sage_helper import _within_sage, sage_method
|
|
13
|
+
from spherogram import Link
|
|
14
|
+
from .nsagetools import (join_lists,
|
|
15
|
+
minimum_exponents,
|
|
16
|
+
fox_derivative,
|
|
17
|
+
uniform_poly_exponents,
|
|
18
|
+
convert_laurent_to_poly,
|
|
19
|
+
alexander_polynomial_basic,
|
|
20
|
+
MapToFreeAbelianization,
|
|
21
|
+
MapToGroupRingOfFreeAbelianization)
|
|
22
|
+
|
|
23
|
+
if _within_sage:
|
|
24
|
+
from ..sage_helper import gcd, matrix, QQ, ZZ, PolynomialRing
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def standard_map_to_group_ring_of_abelianization_for_link(manifold_group):
|
|
28
|
+
"""
|
|
29
|
+
Assumes the given manifold group come from an n-cusped manifold
|
|
30
|
+
with H_1 = Z^n + torsion where a Z-basis for the Z^n part is given
|
|
31
|
+
by the meridians on each cusp::
|
|
32
|
+
|
|
33
|
+
sage: G = Link('L14a25429').exterior().fundamental_group()
|
|
34
|
+
sage: phi = standard_map_to_group_ring_of_abelianization_for_link(G)
|
|
35
|
+
sage: phi(''.join(m for m, l in G.peripheral_curves()))
|
|
36
|
+
a*b*c
|
|
37
|
+
"""
|
|
38
|
+
G = manifold_group
|
|
39
|
+
phi = MapToGroupRingOfFreeAbelianization(G)
|
|
40
|
+
R = phi.range()
|
|
41
|
+
betti = R.ngens()
|
|
42
|
+
meridians = [m for m, l in G.peripheral_curves()]
|
|
43
|
+
A = matrix(ZZ, [MapToFreeAbelianization.__call__(phi, m) for m in meridians])
|
|
44
|
+
if not (len(meridians) == phi.U.nrows() == betti and A.is_invertible()):
|
|
45
|
+
raise ValueError('H_1 or meridians incompatible being the exterior of a link in S^3.')
|
|
46
|
+
A = A.transpose().inverse()
|
|
47
|
+
phi = MapToGroupRingOfFreeAbelianization(G)
|
|
48
|
+
phi.U = A * phi.U
|
|
49
|
+
assert all(phi(m) == g for m, g in zip(meridians, R.gens()))
|
|
50
|
+
return phi
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def alexander_polynomial_of_link(manifold, d):
|
|
54
|
+
"""
|
|
55
|
+
Compute the d-th Alexander polynomial, i.e. the gcd of the
|
|
56
|
+
(d + 1)-st elementrary ideal of A(M)::
|
|
57
|
+
|
|
58
|
+
sage: L = Link('L5a1')
|
|
59
|
+
sage: f = alexander_polynomial_of_link(L, 0)
|
|
60
|
+
sage: f == L.alexander_polynomial()(*f.parent().gens())
|
|
61
|
+
True
|
|
62
|
+
sage: U1 = Link(braid_closure=[1])
|
|
63
|
+
sage: alexander_polynomial_of_link(U1, 0)
|
|
64
|
+
1
|
|
65
|
+
sage: U2 = Link(braid_closure=[1, -1])
|
|
66
|
+
sage: alexander_polynomial_of_link(U2, 0)
|
|
67
|
+
0
|
|
68
|
+
sage: alexander_polynomial_of_link(U2, 1)
|
|
69
|
+
1
|
|
70
|
+
sage: U4 = Link(braid_closure=[1, -1, 2, -2, 3, -3])
|
|
71
|
+
sage: [alexander_polynomial_of_link(U4, d) for d in range(4)]
|
|
72
|
+
[0, 0, 0, 1]
|
|
73
|
+
sage: M = Link('L12n1181') # Milnor's link, strongly slice.
|
|
74
|
+
sage: alexander_polynomial_of_link(M, 0)
|
|
75
|
+
0
|
|
76
|
+
sage: alexander_polynomial_of_link(M, 1)
|
|
77
|
+
a^2*b + a*b^2 - a^2 - 3*a*b - b^2 + a + b
|
|
78
|
+
"""
|
|
79
|
+
if isinstance(manifold, Link):
|
|
80
|
+
manifold = manifold.exterior()
|
|
81
|
+
G = manifold.fundamental_group()
|
|
82
|
+
phi = standard_map_to_group_ring_of_abelianization_for_link(G)
|
|
83
|
+
return alexander_polynomial_basic(G, phi, d, pos_leading_coeff=True)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def alexander_data(manifold):
|
|
87
|
+
"""
|
|
88
|
+
Consider the Alexander module::
|
|
89
|
+
|
|
90
|
+
A(M) = H_1(univ abelian cover, p^{-1}(point)).
|
|
91
|
+
|
|
92
|
+
Returns the pair (d, p(t_1, ... , t_k)) where:
|
|
93
|
+
|
|
94
|
+
i) d is the Alexander nullity, that is, rank(A(M)) - 1, and
|
|
95
|
+
|
|
96
|
+
ii) p is the d^th Alexander polynomial, that is, the gcd of
|
|
97
|
+
the (d + 1)st elementrary ideal of A(M).
|
|
98
|
+
|
|
99
|
+
Some examples::
|
|
100
|
+
|
|
101
|
+
sage: U1 = Link(braid_closure=[1])
|
|
102
|
+
sage: alexander_data(U1)
|
|
103
|
+
(0, 1)
|
|
104
|
+
sage: U2 = Link(braid_closure=[1, -1])
|
|
105
|
+
sage: alexander_data(U2)
|
|
106
|
+
(1, 1)
|
|
107
|
+
sage: U4 = Link(braid_closure=[1, -1, 2, -2, 3, -3])
|
|
108
|
+
sage: alexander_data(U4)
|
|
109
|
+
(3, 1)
|
|
110
|
+
sage: M = Link('L12n1181')
|
|
111
|
+
sage: alexander_data(M)
|
|
112
|
+
(1, a^2*b + a*b^2 - a^2 - 3*a*b - b^2 + a + b)
|
|
113
|
+
"""
|
|
114
|
+
if isinstance(manifold, Link):
|
|
115
|
+
manifold = manifold.exterior()
|
|
116
|
+
M = manifold
|
|
117
|
+
for d in range(M.num_cusps()):
|
|
118
|
+
alex = alexander_polynomial_of_link(M, d)
|
|
119
|
+
if alex != 0:
|
|
120
|
+
return (d, alex)
|
|
121
|
+
|
|
122
|
+
def normalize(poly):
|
|
123
|
+
"""
|
|
124
|
+
Divide the polynomial by the largest mononomial that divides every
|
|
125
|
+
term::
|
|
126
|
+
|
|
127
|
+
sage: P = PolynomialRing(QQ, 'x')
|
|
128
|
+
sage: normalize(P('x^3 + 2*x^2 + 3*x'))
|
|
129
|
+
x^2 + 2*x + 3
|
|
130
|
+
sage: R = PolynomialRing(QQ, ['a', 'b'])
|
|
131
|
+
sage: normalize(R('2*a^3*b + a*b^2 + 3*a*b'))
|
|
132
|
+
2*a^2 + b + 3
|
|
133
|
+
"""
|
|
134
|
+
if poly.is_constant():
|
|
135
|
+
return poly
|
|
136
|
+
|
|
137
|
+
P = poly.parent()
|
|
138
|
+
if P.ngens() == 1:
|
|
139
|
+
m = min(poly.exponents())
|
|
140
|
+
return P({e - m:c for e, c in poly.dict().items()})
|
|
141
|
+
else:
|
|
142
|
+
n = P.ngens()
|
|
143
|
+
exps = poly.exponents()
|
|
144
|
+
mins = [min(e[i] for e in exps) for i in range(n)]
|
|
145
|
+
return P({tuple(e - m for e, m in zip(exps, mins)): c
|
|
146
|
+
for exps, c in poly.dict().items()})
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def palindrome(poly):
|
|
150
|
+
"""
|
|
151
|
+
For f in R[t_1, ... , t_n] compute f(1/t_1, ..., 1/t_n) and return
|
|
152
|
+
it times the minimal monomial that puts it in R[t_1, ... , t_n]::
|
|
153
|
+
|
|
154
|
+
sage: P = PolynomialRing(ZZ, 'x')
|
|
155
|
+
sage: palindrome(P(1))
|
|
156
|
+
1
|
|
157
|
+
sage: palindrome(P('x^3 + 2*x^2 + 3*x'))
|
|
158
|
+
3*x^2 + 2*x + 1
|
|
159
|
+
sage: R = PolynomialRing(ZZ, ['a', 'b'])
|
|
160
|
+
sage: palindrome(R(2))
|
|
161
|
+
2
|
|
162
|
+
sage: palindrome(R('2*a^3*b + a*b^2 + 3*a*b'))
|
|
163
|
+
3*a^2*b + a^2 + 2*b
|
|
164
|
+
"""
|
|
165
|
+
if poly.is_constant():
|
|
166
|
+
return poly
|
|
167
|
+
|
|
168
|
+
P = poly.parent()
|
|
169
|
+
if P.ngens() == 1:
|
|
170
|
+
m = poly.degree()
|
|
171
|
+
return P({m - e:c for e, c in poly.dict().items()})
|
|
172
|
+
else:
|
|
173
|
+
n = P.ngens()
|
|
174
|
+
exps = poly.exponents()
|
|
175
|
+
maxes = [max(e[i] for e in exps) for i in range(n)]
|
|
176
|
+
return P({tuple(m - e for m, e in zip(maxes, exps)): c
|
|
177
|
+
for exps, c in poly.dict().items()})
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def is_palindrome(poly):
|
|
181
|
+
return normalize(poly) == palindrome(poly)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def poly_is_a_norm(poly):
|
|
185
|
+
"""
|
|
186
|
+
Given a poly in ZZ[t_1, ... , t_n], determines if the poly is of
|
|
187
|
+
the form f * palindrome(f) up to units where f(1, 1, ... , 1) is
|
|
188
|
+
+/-1.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
if poly == 0:
|
|
192
|
+
return False
|
|
193
|
+
P = poly.parent()
|
|
194
|
+
assert P.base_ring() == ZZ
|
|
195
|
+
n = poly.parent().ngens()
|
|
196
|
+
|
|
197
|
+
ones = n*[1]
|
|
198
|
+
val_at_ones = poly(ones)
|
|
199
|
+
if val_at_ones < 0:
|
|
200
|
+
poly, val_at_ones = -poly, -val_at_ones
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if val_at_ones != 1:
|
|
204
|
+
return False
|
|
205
|
+
|
|
206
|
+
facs = []
|
|
207
|
+
g = P(1)
|
|
208
|
+
for f, e in poly.factor():
|
|
209
|
+
assert abs(f(ones)) == 1
|
|
210
|
+
if f(ones) < 0:
|
|
211
|
+
f = -f
|
|
212
|
+
facs.append((f, e))
|
|
213
|
+
g = g * f**e
|
|
214
|
+
|
|
215
|
+
assert g == poly
|
|
216
|
+
|
|
217
|
+
for f, e in facs:
|
|
218
|
+
if is_palindrome(f):
|
|
219
|
+
if e % 2 != 0:
|
|
220
|
+
return False
|
|
221
|
+
else:
|
|
222
|
+
g = palindrome(f)
|
|
223
|
+
if not (g, e) in facs:
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
return True
|
|
227
|
+
|
|
228
|
+
@sage_method
|
|
229
|
+
def fox_milnor_test(manifold_or_link):
|
|
230
|
+
"""
|
|
231
|
+
Returns ``True`` when the Alexander polynomial data of the link is
|
|
232
|
+
compatible with it being topologically strongly slice (that is,
|
|
233
|
+
the link bounds a disjoint collection of locally-flat disks in the
|
|
234
|
+
4-ball). More precisely, it checks if the Alexander nullity is as
|
|
235
|
+
expected and that the appropriate Alexander polynomial is a norm::
|
|
236
|
+
|
|
237
|
+
sage: mflds = [Manifold('L12n1181'), Manifold('L11n247'), Manifold('L10n107')]
|
|
238
|
+
sage: {M.alexander_polynomial() for M in mflds}
|
|
239
|
+
{0}
|
|
240
|
+
sage: [M.fox_milnor_test() for M in mflds]
|
|
241
|
+
[True, False, False]
|
|
242
|
+
|
|
243
|
+
Note: This method only requires that the homology (including the
|
|
244
|
+
meridians) is consistent being the complement of a link in S^3. It
|
|
245
|
+
does not check that the manifold is actually a link complement.
|
|
246
|
+
|
|
247
|
+
References: This test is Corollary 12.3.14 of `[Kawauchi]
|
|
248
|
+
<https://doi.org/10.1007/978-3-0348-9227-8>`_ and Theorem 8.18 of
|
|
249
|
+
`[Lickorish] <https://doi.org/10.1007/978-1-4612-0691-0>`_.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
M = manifold_or_link
|
|
253
|
+
if isinstance(M, Link):
|
|
254
|
+
M = M.exterior()
|
|
255
|
+
|
|
256
|
+
if not all(M.cusp_info('is_complete')):
|
|
257
|
+
raise ValueError('All cusps must be unfilled.')
|
|
258
|
+
|
|
259
|
+
if M.homology().elementary_divisors() != M.num_cusps()*[0]:
|
|
260
|
+
raise ValueError('Homology is not Z^(number of cusps).')
|
|
261
|
+
|
|
262
|
+
nullity, alex = alexander_data(M)
|
|
263
|
+
if nullity != M.num_cusps() - 1:
|
|
264
|
+
return False
|
|
265
|
+
return poly_is_a_norm(alex)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == '__main__':
|
|
270
|
+
import doctest
|
|
271
|
+
print(doctest.testmod())
|