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,995 @@
|
|
|
1
|
+
from . import matrix
|
|
2
|
+
from . import homology
|
|
3
|
+
from .polynomial import Polynomial
|
|
4
|
+
from .ptolemyObstructionClass import PtolemyObstructionClass
|
|
5
|
+
from .ptolemyGeneralizedObstructionClass import PtolemyGeneralizedObstructionClass
|
|
6
|
+
from .ptolemyVarietyPrimeIdealGroebnerBasis import PtolemyVarietyPrimeIdealGroebnerBasis
|
|
7
|
+
from . import processFileBase, processFileDispatch, processMagmaFile
|
|
8
|
+
from .processFileBase import PtolemyPrecomputedObstructionClassMismatchError
|
|
9
|
+
from . import utilities
|
|
10
|
+
from ..sage_helper import _within_sage, sage_method
|
|
11
|
+
from string import Template
|
|
12
|
+
import signal
|
|
13
|
+
import re
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
if _within_sage:
|
|
18
|
+
from sage.rings.rational_field import RationalField
|
|
19
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
20
|
+
from sage.rings.ideal import Ideal
|
|
21
|
+
|
|
22
|
+
from urllib.request import Request, urlopen
|
|
23
|
+
from urllib.request import quote as urlquote
|
|
24
|
+
from urllib.error import HTTPError
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PtolemyFileMissingError(Exception):
|
|
28
|
+
"""
|
|
29
|
+
An exception indicating that a requested solution file was missing.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, message):
|
|
33
|
+
Exception.__init__(self, message)
|
|
34
|
+
|
|
35
|
+
class PtolemyMissingFileForObstructionClass(Exception):
|
|
36
|
+
def __init__(self, index):
|
|
37
|
+
|
|
38
|
+
msg = (
|
|
39
|
+
"Pari's implementation of the Smith normal form has changed "
|
|
40
|
+
"affecting the order in which the cohomology classes are listed "
|
|
41
|
+
"and the cocycles used to represent them. Unfortunately, the "
|
|
42
|
+
"pre-computed file uses a cocycle that no longer matches and "
|
|
43
|
+
"a file matching the new cocycle has not yet been produced. "
|
|
44
|
+
"Please report the manifold and index (%d)." % index)
|
|
45
|
+
Exception.__init__(self, msg)
|
|
46
|
+
self.index = index
|
|
47
|
+
|
|
48
|
+
class PtolemyVariety():
|
|
49
|
+
"""
|
|
50
|
+
Holds a reduced Ptolemy variety.
|
|
51
|
+
|
|
52
|
+
=== Examples ===
|
|
53
|
+
|
|
54
|
+
To generate such a variety, call:
|
|
55
|
+
|
|
56
|
+
>>> from snappy import Manifold
|
|
57
|
+
>>> p = Manifold("4_1").ptolemy_variety(2, obstruction_class = 1)
|
|
58
|
+
|
|
59
|
+
Show the equations and variables:
|
|
60
|
+
|
|
61
|
+
>>> for e in p.equations: print(e)
|
|
62
|
+
- c_0011_0 * c_0101_0 + c_0011_0^2 + c_0101_0^2
|
|
63
|
+
c_0011_0 * c_0101_0 - c_0011_0^2 - c_0101_0^2
|
|
64
|
+
- 1 + c_0011_0
|
|
65
|
+
>>> p.variables
|
|
66
|
+
['c_0011_0', 'c_0101_0']
|
|
67
|
+
|
|
68
|
+
Show as an ideal (sage object):
|
|
69
|
+
|
|
70
|
+
>>> p.ideal #doctest: +SKIP
|
|
71
|
+
Ideal (-c_0011_0^2 + c_0011_0*c_0101_0 + c_0101_0^2, -c_0011_0^2 - c_0011_0*c_0101_0 + c_0101_0^2, c_0011_0 - 1) of Multivariate Polynomial Ring in c_0011_0, c_0101_0 over Rational Field
|
|
72
|
+
(skip doctest because example only works in sage and not plain python)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
Produce magma input:
|
|
76
|
+
|
|
77
|
+
>>> s = p.to_magma()
|
|
78
|
+
>>> print(s.split('ring and ideal')[1].strip()) #doctest: +ELLIPSIS
|
|
79
|
+
R<c_0011_0, c_0101_0> := PolynomialRing(RationalField(), 2, "grevlex");
|
|
80
|
+
MyIdeal := ideal<R |
|
|
81
|
+
- c_0011_0 * c_0101_0 + c_0011_0^2 + c_0101_0^2,
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
Call ``p.compute_solutions()`` to automatically compute solutions!
|
|
85
|
+
|
|
86
|
+
Show canonical representatives:
|
|
87
|
+
|
|
88
|
+
(The Ptolemy coordinates c_0110_0 and c_0101_0 are identified, this
|
|
89
|
+
information is needed to recover all Ptolemy coordinates from the solutions
|
|
90
|
+
of a simplified Ptolemy variety. The information is also packaged into a
|
|
91
|
+
python section by py_eval_variable_dict().)
|
|
92
|
+
|
|
93
|
+
>>> p.canonical_representative["c_0110_0"]
|
|
94
|
+
(1, 0, 'c_0101_0')
|
|
95
|
+
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, manifold, N, obstruction_class,
|
|
99
|
+
simplify, eliminate_fixed_ptolemys):
|
|
100
|
+
self._manifold = manifold
|
|
101
|
+
self._N = N
|
|
102
|
+
self._obstruction_class = obstruction_class
|
|
103
|
+
|
|
104
|
+
if obstruction_class:
|
|
105
|
+
obstruction_class._checkManifoldAndN(manifold, N)
|
|
106
|
+
|
|
107
|
+
if isinstance(obstruction_class, PtolemyObstructionClass):
|
|
108
|
+
self._identified_variables_from_obstruction = (
|
|
109
|
+
obstruction_class.identified_variables)
|
|
110
|
+
else:
|
|
111
|
+
self._identified_variables_from_obstruction = [ ]
|
|
112
|
+
|
|
113
|
+
H2_class = None
|
|
114
|
+
|
|
115
|
+
if isinstance(obstruction_class, PtolemyGeneralizedObstructionClass):
|
|
116
|
+
H2_class = obstruction_class.H2_class
|
|
117
|
+
|
|
118
|
+
self._identified_coordinates = (
|
|
119
|
+
manifold._ptolemy_equations_identified_coordinates(N, H2_class))
|
|
120
|
+
|
|
121
|
+
self._action_by_decoration_change = (
|
|
122
|
+
manifold._ptolemy_equations_action_by_decoration_change(N))
|
|
123
|
+
|
|
124
|
+
# find enough Ptolemy variables to set to one so that the
|
|
125
|
+
# decoration is fixed
|
|
126
|
+
self._fixed_ptolemy_coordinates = (
|
|
127
|
+
_fix_decoration(N, self._action_by_decoration_change))
|
|
128
|
+
|
|
129
|
+
self._identified_variables = (
|
|
130
|
+
self._identified_coordinates +
|
|
131
|
+
self._identified_variables_from_obstruction)
|
|
132
|
+
|
|
133
|
+
self._ptolemy_relations = (
|
|
134
|
+
_generate_ptolemy_relations(
|
|
135
|
+
N, manifold.num_tetrahedra(),
|
|
136
|
+
isinstance(obstruction_class, PtolemyObstructionClass)))
|
|
137
|
+
|
|
138
|
+
self.equations = list(self._ptolemy_relations)
|
|
139
|
+
|
|
140
|
+
order_of_u = 1
|
|
141
|
+
|
|
142
|
+
if isinstance(obstruction_class, PtolemyGeneralizedObstructionClass):
|
|
143
|
+
order_of_u, equations = (
|
|
144
|
+
obstruction_class._get_equation_for_u(N))
|
|
145
|
+
self.equations += equations
|
|
146
|
+
|
|
147
|
+
if eliminate_fixed_ptolemys:
|
|
148
|
+
|
|
149
|
+
# each ptolemy set to 1 for fixing decoration is eliminated by
|
|
150
|
+
# being replace by 1
|
|
151
|
+
self._identified_variables += (
|
|
152
|
+
[ (+1, 0, ptolemy_coord, 1)
|
|
153
|
+
for ptolemy_coord in self._fixed_ptolemy_coordinates])
|
|
154
|
+
|
|
155
|
+
else:
|
|
156
|
+
one = Polynomial.constant_polynomial(1)
|
|
157
|
+
|
|
158
|
+
# we add an equation c_XXXX_X - 1 for enough ptolemy's
|
|
159
|
+
# to fix the decoration
|
|
160
|
+
self.equations += (
|
|
161
|
+
[ Polynomial.from_variable_name(ptolemy_coord) - one
|
|
162
|
+
for ptolemy_coord in self._fixed_ptolemy_coordinates])
|
|
163
|
+
|
|
164
|
+
variables = _union(eqn.variables() for eqn in self.equations)
|
|
165
|
+
|
|
166
|
+
if simplify:
|
|
167
|
+
|
|
168
|
+
self.canonical_representative = _identified_variables_canonize(
|
|
169
|
+
self._identified_variables)
|
|
170
|
+
|
|
171
|
+
substitution = (
|
|
172
|
+
_canonical_representative_to_polynomial_substituition(
|
|
173
|
+
self.canonical_representative, order_of_u))
|
|
174
|
+
|
|
175
|
+
self.equations = [eqn.substitute(substitution)
|
|
176
|
+
for eqn in self.equations]
|
|
177
|
+
|
|
178
|
+
else:
|
|
179
|
+
|
|
180
|
+
self.canonical_representative = { }
|
|
181
|
+
|
|
182
|
+
for sign, power, var1, var2 in self._identified_variables:
|
|
183
|
+
|
|
184
|
+
self.canonical_representative[var1] = (+1, 0, var1)
|
|
185
|
+
if var2 != 1:
|
|
186
|
+
self.canonical_representative[var2] = (+1, 0, var2)
|
|
187
|
+
|
|
188
|
+
if order_of_u == 2:
|
|
189
|
+
u = Polynomial.constant_polynomial(-1)
|
|
190
|
+
else:
|
|
191
|
+
u = Polynomial.from_variable_name('u')
|
|
192
|
+
|
|
193
|
+
firstTerm = (
|
|
194
|
+
Polynomial.from_variable_name(var1) *
|
|
195
|
+
u ** (power % order_of_u))
|
|
196
|
+
|
|
197
|
+
if var2 == 1:
|
|
198
|
+
secondTerm = (
|
|
199
|
+
Polynomial.constant_polynomial(sign))
|
|
200
|
+
else:
|
|
201
|
+
secondTerm = (
|
|
202
|
+
Polynomial.constant_polynomial(sign) *
|
|
203
|
+
Polynomial.from_variable_name(var2))
|
|
204
|
+
self.equations.append(firstTerm - secondTerm)
|
|
205
|
+
|
|
206
|
+
self.variables = _union(eqn.variables() for eqn in self.equations)
|
|
207
|
+
|
|
208
|
+
# Process interior Ptolemy coordinates such as c_1111_x
|
|
209
|
+
# Only invoked for N >= 4
|
|
210
|
+
for var in self.variables:
|
|
211
|
+
if var[0:2] == 'c_':
|
|
212
|
+
if var not in self.canonical_representative:
|
|
213
|
+
self.canonical_representative[var] = (+1, 0, var)
|
|
214
|
+
|
|
215
|
+
self.variables_with_non_zero_condition = [ "t" ] + self.variables
|
|
216
|
+
|
|
217
|
+
# take out u, the root of unity
|
|
218
|
+
vars_without_u = [ var
|
|
219
|
+
for var in self.variables_with_non_zero_condition
|
|
220
|
+
if not var == 'u']
|
|
221
|
+
|
|
222
|
+
self._non_zero_condition = (
|
|
223
|
+
_non_zero_condition(vars_without_u))
|
|
224
|
+
|
|
225
|
+
self.equations_with_non_zero_condition = (
|
|
226
|
+
self.equations + [ self._non_zero_condition ])
|
|
227
|
+
|
|
228
|
+
if _within_sage:
|
|
229
|
+
self.ideal = _sage_ideal(
|
|
230
|
+
self.variables,
|
|
231
|
+
self.equations)
|
|
232
|
+
|
|
233
|
+
self.ideal_with_non_zero_condition = _sage_ideal(
|
|
234
|
+
self.variables_with_non_zero_condition,
|
|
235
|
+
self.equations_with_non_zero_condition)
|
|
236
|
+
|
|
237
|
+
def py_eval_variable_dict(self):
|
|
238
|
+
|
|
239
|
+
def create_dict_entry(var1, val):
|
|
240
|
+
sign, power, var2 = val
|
|
241
|
+
|
|
242
|
+
assert sign in [+1, -1]
|
|
243
|
+
|
|
244
|
+
p = ""
|
|
245
|
+
if self._N == 2:
|
|
246
|
+
sign *= (-1) ** power
|
|
247
|
+
else:
|
|
248
|
+
if power % self._N:
|
|
249
|
+
p = " * d['u'] ** %d" % (power % self._N)
|
|
250
|
+
|
|
251
|
+
if sign == +1:
|
|
252
|
+
return "'%s' : d['%s']%s" % (var1, var2, p)
|
|
253
|
+
else:
|
|
254
|
+
return "'%s' : - d['%s']%s" % (var1, var2, p)
|
|
255
|
+
|
|
256
|
+
format_str = "(lambda d: {\n %s})"
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
format_str % ',\n '.join(
|
|
260
|
+
[create_dict_entry(key, val)
|
|
261
|
+
for key, val
|
|
262
|
+
in list(self.canonical_representative.items())
|
|
263
|
+
if not key == 1]))
|
|
264
|
+
|
|
265
|
+
def py_eval_section(self):
|
|
266
|
+
"""
|
|
267
|
+
Returns a string that can be evaluated in python and contains extra
|
|
268
|
+
information needed to recover solutions from a simplified Ptolemy
|
|
269
|
+
variety.
|
|
270
|
+
|
|
271
|
+
>>> from snappy import Manifold, pari
|
|
272
|
+
>>> M = Manifold('4_1')
|
|
273
|
+
>>> p = M.ptolemy_variety(2, obstruction_class = 1)
|
|
274
|
+
|
|
275
|
+
Get extra information
|
|
276
|
+
|
|
277
|
+
>>> eval_section = p.py_eval_section()
|
|
278
|
+
>>> print(eval_section) #doctest: +ELLIPSIS
|
|
279
|
+
{'variable_dict' :
|
|
280
|
+
(lambda d: {
|
|
281
|
+
...
|
|
282
|
+
|
|
283
|
+
Turn it into a python object by evaluation.
|
|
284
|
+
|
|
285
|
+
>>> obj = eval(eval_section)
|
|
286
|
+
|
|
287
|
+
Access the function that expands a solution to the simplified
|
|
288
|
+
Ptolemy variety to a full solution.
|
|
289
|
+
|
|
290
|
+
>>> variable_dict = obj['variable_dict']
|
|
291
|
+
|
|
292
|
+
Setup a solution and expand it to a full solution, '1' must map to 1
|
|
293
|
+
|
|
294
|
+
>>> simplified_solution = {'c_0101_0' : pari('0.5 - 0.866025403784439*I'), '1' : pari(1), 'c_0011_0' : pari(1)}
|
|
295
|
+
>>> full_solution = variable_dict(simplified_solution)
|
|
296
|
+
|
|
297
|
+
Full solution is a dictionary with a key for every Ptolemy coordinate
|
|
298
|
+
|
|
299
|
+
>>> full_solution['c_1010_1']
|
|
300
|
+
1
|
|
301
|
+
>>> for tet in range(2):
|
|
302
|
+
... for i in utilities.quadruples_with_fixed_sum_iterator(2, skipVertices = True):
|
|
303
|
+
... c = "c_%d%d%d%d" % i + "_%d" % tet
|
|
304
|
+
... assert c in full_solution
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
result = "{"
|
|
308
|
+
result += "'variable_dict' :\n %s" % self.py_eval_variable_dict()
|
|
309
|
+
|
|
310
|
+
# If we have a non-trivial generalized obstruction class,
|
|
311
|
+
# add an extra key to the dictionary to mark it.
|
|
312
|
+
|
|
313
|
+
# This will prevent PtolemyCoordinates to compute the ill-defined
|
|
314
|
+
# flattenings and complex volume.
|
|
315
|
+
|
|
316
|
+
if isinstance(self._obstruction_class,
|
|
317
|
+
PtolemyGeneralizedObstructionClass):
|
|
318
|
+
if self._obstruction_class._is_non_trivial(self._N):
|
|
319
|
+
result += (
|
|
320
|
+
",\n "
|
|
321
|
+
"'non_trivial_generalized_obstruction_class' : True")
|
|
322
|
+
|
|
323
|
+
result += "}"
|
|
324
|
+
|
|
325
|
+
return result
|
|
326
|
+
|
|
327
|
+
def to_magma_file(
|
|
328
|
+
self, filename,
|
|
329
|
+
template_path="magma/default.magma_template"):
|
|
330
|
+
"""
|
|
331
|
+
>>> import os, tempfile
|
|
332
|
+
>>> from snappy import Manifold
|
|
333
|
+
>>> handle, name = tempfile.mkstemp()
|
|
334
|
+
>>> p = Manifold("4_1").ptolemy_variety(2, obstruction_class=1)
|
|
335
|
+
>>> p.to_magma_file(name)
|
|
336
|
+
>>> os.close(handle); os.remove(name)
|
|
337
|
+
"""
|
|
338
|
+
with open(filename, 'wb') as output:
|
|
339
|
+
output.write(bytes(self.to_magma(template_path=template_path).encode('ascii')))
|
|
340
|
+
|
|
341
|
+
def to_magma(
|
|
342
|
+
self,
|
|
343
|
+
template_path="magma/default.magma_template"):
|
|
344
|
+
"""
|
|
345
|
+
Returns a string with the ideal that can be used as input for magma.
|
|
346
|
+
|
|
347
|
+
The advanced user can provide a template string to write own magma
|
|
348
|
+
code to process the equations.
|
|
349
|
+
|
|
350
|
+
>>> from snappy import *
|
|
351
|
+
>>> p = Manifold("4_1").ptolemy_variety(2, obstruction_class = 1)
|
|
352
|
+
|
|
353
|
+
Magma input to compute radical Decomposition
|
|
354
|
+
>>> s = p.to_magma()
|
|
355
|
+
>>> print(s.split('ring and ideal')[1].strip()) #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
|
356
|
+
R<c_0011_0, c_0101_0> := PolynomialRing(RationalField(), 2, "grevlex");
|
|
357
|
+
MyIdeal := ideal<R | - c_0011_0 * c_0101_0 + c_0011_0^2 + c_0101_0^2,
|
|
358
|
+
...
|
|
359
|
+
>>> "RadicalDecomposition" in p.to_magma()
|
|
360
|
+
True
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
if os.path.isfile(template_path):
|
|
364
|
+
template = open(template_path, 'r').read()
|
|
365
|
+
else:
|
|
366
|
+
from snappy.ptolemy import __path__ as base_paths
|
|
367
|
+
abs_path = os.path.join(base_paths[0], template_path)
|
|
368
|
+
if os.path.isfile(abs_path):
|
|
369
|
+
template = open(abs_path, 'r').read()
|
|
370
|
+
else:
|
|
371
|
+
raise Exception("No file at template_path %s" % template_path)
|
|
372
|
+
|
|
373
|
+
PREAMBLE = (
|
|
374
|
+
"==TRIANGULATION=BEGINS==\n" +
|
|
375
|
+
self._manifold._to_string() + "\n"
|
|
376
|
+
"==TRIANGULATION=ENDS==\n" +
|
|
377
|
+
"PY=EVAL=SECTION=BEGINS=HERE\n" +
|
|
378
|
+
self.py_eval_section() + "\n"
|
|
379
|
+
"PY=EVAL=SECTION=ENDS=HERE\n")
|
|
380
|
+
|
|
381
|
+
# magma will wrap long lines and we potentially lose some information
|
|
382
|
+
# that way when retrieving the ASCII text encoding the triangulation
|
|
383
|
+
# and the py_eval dictionary.
|
|
384
|
+
# To prevent this, we already break long lines here in such a way that
|
|
385
|
+
# join_long_lines gives exactly back the same ASCII text.
|
|
386
|
+
|
|
387
|
+
# Next, we quote the text so that we can give it to magma's print.
|
|
388
|
+
|
|
389
|
+
QUOTED_PREAMBLE = utilities.quote_ascii_text(
|
|
390
|
+
utilities.break_long_lines(PREAMBLE))
|
|
391
|
+
|
|
392
|
+
return Template(template).safe_substitute(
|
|
393
|
+
PREAMBLE=PREAMBLE,
|
|
394
|
+
QUOTED_PREAMBLE=QUOTED_PREAMBLE,
|
|
395
|
+
|
|
396
|
+
VARIABLES=(
|
|
397
|
+
", ".join(self.variables)),
|
|
398
|
+
VARIABLES_QUOTED=(
|
|
399
|
+
", ".join(['"%s"' % v for v in self.variables])),
|
|
400
|
+
VARIABLE_NUMBER=(
|
|
401
|
+
len(self.variables)),
|
|
402
|
+
|
|
403
|
+
VARIABLES_WITH_NON_ZERO_CONDITION=(
|
|
404
|
+
", ".join(self.variables_with_non_zero_condition)),
|
|
405
|
+
VARIABLES_WITH_NON_ZERO_CONDITION_QUOTED=(
|
|
406
|
+
", ".join(['"%s"' % v
|
|
407
|
+
for v in self.variables_with_non_zero_condition])),
|
|
408
|
+
VARIABLE_WITH_NON_ZERO_CONDITION_NUMBER=(
|
|
409
|
+
len(self.variables_with_non_zero_condition)),
|
|
410
|
+
|
|
411
|
+
EQUATIONS=(
|
|
412
|
+
',\n '.join(
|
|
413
|
+
[str(eqn)
|
|
414
|
+
for eqn in self.equations])),
|
|
415
|
+
EQUATIONS_WITH_NON_ZERO_CONDITION=(
|
|
416
|
+
',\n '.join(
|
|
417
|
+
[str(eqn)
|
|
418
|
+
for eqn in self.equations_with_non_zero_condition])))
|
|
419
|
+
|
|
420
|
+
def filename_base(self):
|
|
421
|
+
"""
|
|
422
|
+
Preferred filename base for writing out this Ptolemy variety
|
|
423
|
+
|
|
424
|
+
>>> from snappy import *
|
|
425
|
+
>>> M = Manifold('4_1')
|
|
426
|
+
>>> p = M.ptolemy_variety(2, obstruction_class = 1)
|
|
427
|
+
>>> p.filename_base()
|
|
428
|
+
'4_1__sl2_c1'
|
|
429
|
+
|
|
430
|
+
>>> p = M.ptolemy_variety(2)
|
|
431
|
+
>>> p.filename_base()
|
|
432
|
+
'4_1__sl2_c0'
|
|
433
|
+
"""
|
|
434
|
+
|
|
435
|
+
obstruction_class = "NoIndex"
|
|
436
|
+
|
|
437
|
+
if self._obstruction_class is None:
|
|
438
|
+
obstruction_class = "0"
|
|
439
|
+
elif self._obstruction_class._index is not None:
|
|
440
|
+
obstruction_class = "%d" % self._obstruction_class._index
|
|
441
|
+
# filenames which contain regex special characters cause
|
|
442
|
+
# trouble with PyInstaller's globbing module.
|
|
443
|
+
name = self._manifold.name().replace('[', '_').replace(']', '')
|
|
444
|
+
return '%s__sl%d_c%s' % (name, self._N, obstruction_class)
|
|
445
|
+
|
|
446
|
+
def path_to_file(self):
|
|
447
|
+
|
|
448
|
+
name = self._manifold.name()
|
|
449
|
+
|
|
450
|
+
if re.match(r'([msvt]|o9_)[0-9]+$', name):
|
|
451
|
+
dir = 'OrientableCuspedCensus'
|
|
452
|
+
elif re.match(r'[0-9]+([\^][0-9]+)?[_][0-9]+$', name):
|
|
453
|
+
dir = 'LinkExteriors'
|
|
454
|
+
elif re.match(r'[KL][0-9]+[an][0-9]+$', name):
|
|
455
|
+
dir = 'HTLinkExteriors'
|
|
456
|
+
else:
|
|
457
|
+
raise Exception('No canonical path for manifold')
|
|
458
|
+
|
|
459
|
+
tets = self._manifold.num_tetrahedra()
|
|
460
|
+
|
|
461
|
+
return '/'.join(['data',
|
|
462
|
+
'pgl%d' % self._N,
|
|
463
|
+
dir,
|
|
464
|
+
'%02d_tetrahedra' % tets])
|
|
465
|
+
|
|
466
|
+
def _solution_file_url(self, alt=0, ext='magma_out', data_url=None):
|
|
467
|
+
|
|
468
|
+
if data_url is None:
|
|
469
|
+
from . import DATA_URL as data_url
|
|
470
|
+
|
|
471
|
+
if '://' not in data_url:
|
|
472
|
+
# No schema in url, assume file
|
|
473
|
+
if not data_url[0] == '/':
|
|
474
|
+
data_url = '/' + data_url
|
|
475
|
+
data_url = 'file://' + data_url
|
|
476
|
+
|
|
477
|
+
# Make it end in /
|
|
478
|
+
if not data_url[-1] == '/':
|
|
479
|
+
data_url = data_url + '/'
|
|
480
|
+
|
|
481
|
+
if alt > 0:
|
|
482
|
+
suffix = '_alt%d' % alt
|
|
483
|
+
else:
|
|
484
|
+
suffix = ''
|
|
485
|
+
|
|
486
|
+
filename = self.filename_base() + suffix + "." + ext
|
|
487
|
+
|
|
488
|
+
return data_url + self.path_to_file() + '/' + urlquote(filename)
|
|
489
|
+
|
|
490
|
+
def _retrieve_solution_file_alt(self,
|
|
491
|
+
alt=0,
|
|
492
|
+
data_url=None,
|
|
493
|
+
exts=['magma_out', 'rur'],
|
|
494
|
+
verbose=False):
|
|
495
|
+
for i, ext in enumerate(exts):
|
|
496
|
+
url = self._solution_file_url(alt=alt,
|
|
497
|
+
data_url=data_url,
|
|
498
|
+
ext=ext)
|
|
499
|
+
if verbose:
|
|
500
|
+
print("Trying to retrieve solutions from %s ..." % url)
|
|
501
|
+
|
|
502
|
+
try:
|
|
503
|
+
return _retrieve_url(url)
|
|
504
|
+
except PtolemyFileMissingError as e:
|
|
505
|
+
if i == len(exts) - 1:
|
|
506
|
+
raise
|
|
507
|
+
|
|
508
|
+
def _retrieve_solution_file(self,
|
|
509
|
+
data_url=None,
|
|
510
|
+
exts=['magma_out', 'rur'],
|
|
511
|
+
verbose=False):
|
|
512
|
+
|
|
513
|
+
num_alts = 3
|
|
514
|
+
|
|
515
|
+
for alt in range(num_alts):
|
|
516
|
+
try:
|
|
517
|
+
text = self._retrieve_solution_file_alt(alt=alt,
|
|
518
|
+
data_url=data_url,
|
|
519
|
+
exts=exts,
|
|
520
|
+
verbose=verbose)
|
|
521
|
+
self._check_obstruction_class_for_precomputed_file(text)
|
|
522
|
+
return text
|
|
523
|
+
except PtolemyPrecomputedObstructionClassMismatchError as e:
|
|
524
|
+
if alt == num_alts - 1:
|
|
525
|
+
raise
|
|
526
|
+
except PtolemyFileMissingError as e:
|
|
527
|
+
if alt == 0:
|
|
528
|
+
raise
|
|
529
|
+
else:
|
|
530
|
+
raise PtolemyMissingFileForObstructionClass(
|
|
531
|
+
self._obstruction_class._index if self._obstruction_class else 0)
|
|
532
|
+
|
|
533
|
+
def _check_obstruction_class_for_precomputed_file(
|
|
534
|
+
self, text):
|
|
535
|
+
|
|
536
|
+
# Grab the PY=EVAL=SECTION
|
|
537
|
+
# Note that this will be evaluated again later.
|
|
538
|
+
# But it is cheap enough that the double evaluation should not matter.
|
|
539
|
+
py_eval = processFileBase.get_py_eval(text)
|
|
540
|
+
|
|
541
|
+
# Now get the function that takes a dictionary-like object with
|
|
542
|
+
# the solutions to the variety and expands it to a dictionary
|
|
543
|
+
# assigning a value to all Ptolemy coordinates and obstruction class
|
|
544
|
+
# variables.
|
|
545
|
+
variable_dict_function = py_eval['variable_dict']
|
|
546
|
+
|
|
547
|
+
# As noticed by Nathan, the obstruction classes used for producing
|
|
548
|
+
# the pre-computed solutions do not match the obstruction classes
|
|
549
|
+
# we compute now.
|
|
550
|
+
# This is due to pari changing the code for computing the
|
|
551
|
+
# Smith normal form in version 2.13 (see
|
|
552
|
+
# http://pari.math.u-bordeaux.fr/archives/pari-announce-20/msg00006.html)
|
|
553
|
+
#
|
|
554
|
+
# We thus check here explicitly that the obstruction class still
|
|
555
|
+
# matches.
|
|
556
|
+
#
|
|
557
|
+
processFileBase.check_obstruction_class_for_variable_dict_function(
|
|
558
|
+
variable_dict_function,
|
|
559
|
+
self._obstruction_class)
|
|
560
|
+
|
|
561
|
+
def retrieve_decomposition(self, data_url=None, verbose=True):
|
|
562
|
+
|
|
563
|
+
text = self._retrieve_solution_file(data_url,
|
|
564
|
+
exts=['magma_out'],
|
|
565
|
+
verbose=verbose)
|
|
566
|
+
|
|
567
|
+
if verbose:
|
|
568
|
+
print("Parsing...")
|
|
569
|
+
|
|
570
|
+
M = processFileBase.get_manifold(text)
|
|
571
|
+
assert M._to_bytes() == self._manifold._to_bytes(), (
|
|
572
|
+
"Manifold does not match census manifold")
|
|
573
|
+
|
|
574
|
+
return processMagmaFile.decomposition_from_magma(text)
|
|
575
|
+
|
|
576
|
+
def retrieve_solutions(self, numerical=False,
|
|
577
|
+
prefer_rur=False,
|
|
578
|
+
data_url=None,
|
|
579
|
+
verbose=True):
|
|
580
|
+
|
|
581
|
+
exts = ['magma_out.gz', 'magma_out', 'rur']
|
|
582
|
+
if prefer_rur:
|
|
583
|
+
exts = exts[::-1]
|
|
584
|
+
|
|
585
|
+
text = self._retrieve_solution_file(data_url=data_url,
|
|
586
|
+
exts=exts,
|
|
587
|
+
verbose=verbose)
|
|
588
|
+
|
|
589
|
+
if verbose:
|
|
590
|
+
print("Parsing...")
|
|
591
|
+
|
|
592
|
+
M = processFileBase.get_manifold(text)
|
|
593
|
+
assert M._to_bytes() == self._manifold._to_bytes(), (
|
|
594
|
+
"Manifold does not match census manifold")
|
|
595
|
+
|
|
596
|
+
return processFileDispatch.parse_solutions(text, numerical=numerical)
|
|
597
|
+
|
|
598
|
+
def __repr__(self):
|
|
599
|
+
|
|
600
|
+
res = "Ptolemy Variety for %s, N = %d" % (self._manifold.name(),
|
|
601
|
+
self._N)
|
|
602
|
+
if self._obstruction_class is not None:
|
|
603
|
+
res += ", obstruction_class = "
|
|
604
|
+
if self._obstruction_class._index is not None:
|
|
605
|
+
res += "%d" % self._obstruction_class._index
|
|
606
|
+
if isinstance(self._obstruction_class,
|
|
607
|
+
PtolemyGeneralizedObstructionClass):
|
|
608
|
+
res += " (generalized)"
|
|
609
|
+
elif isinstance(self._obstruction_class,
|
|
610
|
+
PtolemyGeneralizedObstructionClass):
|
|
611
|
+
res += "%s" % self._obstruction_class.H2_class
|
|
612
|
+
else:
|
|
613
|
+
res += "..."
|
|
614
|
+
|
|
615
|
+
res += "\n" + "\n".join([' %s' % e for e in self.equations])
|
|
616
|
+
|
|
617
|
+
return res
|
|
618
|
+
|
|
619
|
+
def compute_decomposition(
|
|
620
|
+
self,
|
|
621
|
+
engine=None,
|
|
622
|
+
memory_limit=750000000,
|
|
623
|
+
directory=None,
|
|
624
|
+
verbose=False,
|
|
625
|
+
template_path="magma/default.magma_template"):
|
|
626
|
+
"""
|
|
627
|
+
Starts an engine such as magma to compute the
|
|
628
|
+
radical decomposition of the Ptolemy variety.
|
|
629
|
+
|
|
630
|
+
If started in sage, uses sage, otherwise, uses magma.
|
|
631
|
+
|
|
632
|
+
=== Arguments ===
|
|
633
|
+
|
|
634
|
+
engine --- engine to use, currently, only support magma and sage
|
|
635
|
+
memory_limit --- maximal allowed memory in bytes
|
|
636
|
+
directory --- location for input and output files, temporary directory used if not specified
|
|
637
|
+
verbose --- print extra information
|
|
638
|
+
"""
|
|
639
|
+
|
|
640
|
+
if engine is None:
|
|
641
|
+
if _within_sage:
|
|
642
|
+
engine = 'sage'
|
|
643
|
+
else:
|
|
644
|
+
engine = 'magma'
|
|
645
|
+
|
|
646
|
+
if engine == 'magma':
|
|
647
|
+
return processMagmaFile.run_magma(
|
|
648
|
+
self.to_magma(template_path=template_path),
|
|
649
|
+
filename_base=self.filename_base(),
|
|
650
|
+
memory_limit=memory_limit,
|
|
651
|
+
directory=directory,
|
|
652
|
+
verbose=verbose)
|
|
653
|
+
|
|
654
|
+
if engine == 'sage':
|
|
655
|
+
|
|
656
|
+
M = self._manifold.copy()
|
|
657
|
+
|
|
658
|
+
radical = self.ideal_with_non_zero_condition.radical()
|
|
659
|
+
|
|
660
|
+
sage_radical_decomp = radical.primary_decomposition()
|
|
661
|
+
|
|
662
|
+
def process_component(component):
|
|
663
|
+
|
|
664
|
+
dimension = component.dimension()
|
|
665
|
+
|
|
666
|
+
if dimension == 0:
|
|
667
|
+
sage_gb = component.groebner_basis()
|
|
668
|
+
polys = [ Polynomial.parse_string(str(p)) for p in sage_gb ]
|
|
669
|
+
else:
|
|
670
|
+
polys = []
|
|
671
|
+
|
|
672
|
+
return PtolemyVarietyPrimeIdealGroebnerBasis(
|
|
673
|
+
polys=polys,
|
|
674
|
+
term_order='lex',
|
|
675
|
+
size=None,
|
|
676
|
+
dimension=dimension,
|
|
677
|
+
is_prime=component.is_prime(),
|
|
678
|
+
free_variables=None,
|
|
679
|
+
py_eval=eval(self.py_eval_section()),
|
|
680
|
+
manifold_thunk=lambda :M)
|
|
681
|
+
|
|
682
|
+
return utilities.MethodMappingList(
|
|
683
|
+
[ process_component(component)
|
|
684
|
+
for component in sage_radical_decomp
|
|
685
|
+
if not component.is_one()])
|
|
686
|
+
|
|
687
|
+
def compute_solutions(self,
|
|
688
|
+
engine=None,
|
|
689
|
+
numerical=False,
|
|
690
|
+
template_path="magma/default.magma_template",
|
|
691
|
+
memory_limit=750000000,
|
|
692
|
+
directory=None,
|
|
693
|
+
verbose=False):
|
|
694
|
+
"""
|
|
695
|
+
Starts an engine such as magma to compute the
|
|
696
|
+
radical decomposition of the ideal and computes exact solutions.
|
|
697
|
+
|
|
698
|
+
If started in sage, uses sage, otherwise, uses magma.
|
|
699
|
+
|
|
700
|
+
=== Arguments ===
|
|
701
|
+
|
|
702
|
+
engine --- engine to use, currently, only support magma and sage
|
|
703
|
+
numerical --- get numerical solutions from magma instead of exact ones
|
|
704
|
+
memory_limit --- maximal allowed memory in bytes
|
|
705
|
+
directory --- location for input and output files, temporary directory used if not specified
|
|
706
|
+
verbose --- print extra information
|
|
707
|
+
"""
|
|
708
|
+
|
|
709
|
+
decomposition = self.compute_decomposition(
|
|
710
|
+
engine=engine,
|
|
711
|
+
memory_limit=memory_limit,
|
|
712
|
+
template_path=template_path,
|
|
713
|
+
directory=directory,
|
|
714
|
+
verbose=verbose)
|
|
715
|
+
|
|
716
|
+
return utilities.MethodMappingList(
|
|
717
|
+
[ component.solutions(numerical=numerical)
|
|
718
|
+
for component in decomposition ])
|
|
719
|
+
|
|
720
|
+
def degree_to_shapes(self):
|
|
721
|
+
"""
|
|
722
|
+
In general, there can be d different solutions to the (reduced) Ptolemy
|
|
723
|
+
variety for each solution to the gluing equations (with peripheral
|
|
724
|
+
equations). This method computes d which is also the number of elements
|
|
725
|
+
in H^1(Mhat; Z/N) where Mhat is the non-manifold cell comples obtained
|
|
726
|
+
by gluing together the tetrahedra as non-ideal tetrahedra.
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
For example, the Ptolemy variety for m009 has 4 points but there are
|
|
730
|
+
only 2 distinct boundary-unipotent PSL(2,C) representations.
|
|
731
|
+
Thus the following call returns 2 = 4 / 2
|
|
732
|
+
|
|
733
|
+
>>> from snappy import Manifold
|
|
734
|
+
>>> Manifold("m009").ptolemy_variety(2,1).degree_to_shapes()
|
|
735
|
+
2
|
|
736
|
+
|
|
737
|
+
>>> Manifold("m010").ptolemy_variety(2,1).degree_to_shapes()
|
|
738
|
+
2
|
|
739
|
+
>>> Manifold("m011").ptolemy_variety(2,1).degree_to_shapes()
|
|
740
|
+
1
|
|
741
|
+
|
|
742
|
+
>>> Manifold("m009").ptolemy_variety(3,1).degree_to_shapes()
|
|
743
|
+
1
|
|
744
|
+
>>> Manifold("m010").ptolemy_variety(3,1).degree_to_shapes()
|
|
745
|
+
3
|
|
746
|
+
>>> Manifold("m011").ptolemy_variety(3,1).degree_to_shapes()
|
|
747
|
+
1
|
|
748
|
+
|
|
749
|
+
"""
|
|
750
|
+
|
|
751
|
+
# Boundary maps for chain complex
|
|
752
|
+
d2 = self._manifold._ptolemy_equations_boundary_map_2()[0]
|
|
753
|
+
d1 = self._manifold._ptolemy_equations_boundary_map_1()[0]
|
|
754
|
+
|
|
755
|
+
# Boundary maps for dual chain complex
|
|
756
|
+
co_d1 = matrix.matrix_transpose(d2)
|
|
757
|
+
co_d0 = matrix.matrix_transpose(d1)
|
|
758
|
+
|
|
759
|
+
# All cohomology classes
|
|
760
|
+
cohomology_classes = homology.homology_representatives(
|
|
761
|
+
co_d1, co_d0, self._N)
|
|
762
|
+
|
|
763
|
+
# Number of classes
|
|
764
|
+
return len(list(cohomology_classes))
|
|
765
|
+
|
|
766
|
+
def _fix_decoration(N, action_by_decoration_change):
|
|
767
|
+
|
|
768
|
+
action_matrix, ptolemy_coords, decorations_to_be_fixed = (
|
|
769
|
+
action_by_decoration_change)
|
|
770
|
+
|
|
771
|
+
return matrix.get_independent_rows(
|
|
772
|
+
action_matrix, ptolemy_coords, desired_determinant=N)
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
def _generate_ptolemy_relations(N, num_tet,
|
|
776
|
+
has_obstruction_class):
|
|
777
|
+
|
|
778
|
+
def generate_ptolemy_relation(tet, index):
|
|
779
|
+
|
|
780
|
+
def generate_Ptolemy_coordinate(addl_index):
|
|
781
|
+
total_index = matrix.vector_add(index, addl_index)
|
|
782
|
+
return Polynomial.from_variable_name(
|
|
783
|
+
"c_%d%d%d%d" % tuple(total_index) + "_%d" % tet)
|
|
784
|
+
|
|
785
|
+
def generate_obstruction_variable(face):
|
|
786
|
+
if has_obstruction_class:
|
|
787
|
+
return Polynomial.from_variable_name(
|
|
788
|
+
"s_%d_%d" % (face, tet))
|
|
789
|
+
else:
|
|
790
|
+
return Polynomial.constant_polynomial(1)
|
|
791
|
+
|
|
792
|
+
# implements equation 5.8 from paper
|
|
793
|
+
|
|
794
|
+
return (
|
|
795
|
+
generate_obstruction_variable(0) *
|
|
796
|
+
generate_obstruction_variable(1) *
|
|
797
|
+
generate_Ptolemy_coordinate((1,1,0,0)) *
|
|
798
|
+
generate_Ptolemy_coordinate((0,0,1,1))
|
|
799
|
+
- generate_obstruction_variable(0) *
|
|
800
|
+
generate_obstruction_variable(2) *
|
|
801
|
+
generate_Ptolemy_coordinate((1,0,1,0)) *
|
|
802
|
+
generate_Ptolemy_coordinate((0,1,0,1))
|
|
803
|
+
+ generate_obstruction_variable(0) *
|
|
804
|
+
generate_obstruction_variable(3) *
|
|
805
|
+
generate_Ptolemy_coordinate((1,0,0,1)) *
|
|
806
|
+
generate_Ptolemy_coordinate((0,1,1,0)))
|
|
807
|
+
|
|
808
|
+
return [generate_ptolemy_relation(tet, index)
|
|
809
|
+
for tet in range(num_tet)
|
|
810
|
+
for index in utilities.quadruples_with_fixed_sum_iterator(N-2)]
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def _non_zero_condition(variables):
|
|
814
|
+
one = Polynomial.constant_polynomial(1)
|
|
815
|
+
|
|
816
|
+
polynomial = one
|
|
817
|
+
|
|
818
|
+
for var in variables:
|
|
819
|
+
polynomial = polynomial * Polynomial.from_variable_name(var)
|
|
820
|
+
|
|
821
|
+
polynomial = polynomial - one
|
|
822
|
+
|
|
823
|
+
return polynomial
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
def _union(lists):
|
|
827
|
+
return sorted(set(e for l in lists for e in l))
|
|
828
|
+
|
|
829
|
+
def _identified_variables_canonize(identified_variables):
|
|
830
|
+
|
|
831
|
+
def merge_two_dicts(sign, power, var1, var2, dict1, dict2):
|
|
832
|
+
|
|
833
|
+
sign1, power1 = dict1[var1]
|
|
834
|
+
sign2, power2 = dict2[var2]
|
|
835
|
+
|
|
836
|
+
new_sign = sign1 * sign * sign2
|
|
837
|
+
new_power = power1 - power - power2
|
|
838
|
+
|
|
839
|
+
for v2, (s2, p2) in dict2.items():
|
|
840
|
+
dict1[v2] = (s2 * new_sign, p2 + new_power)
|
|
841
|
+
|
|
842
|
+
return dict1
|
|
843
|
+
|
|
844
|
+
all_variables = {}
|
|
845
|
+
|
|
846
|
+
for sign, power, var1, var2 in identified_variables:
|
|
847
|
+
all_variables[var1] = { var1 : (+1, 0) }
|
|
848
|
+
all_variables[var2] = { var2 : (+1, 0) }
|
|
849
|
+
|
|
850
|
+
for sign, power, var1, var2 in identified_variables:
|
|
851
|
+
if not all_variables[var1] is all_variables[var2]:
|
|
852
|
+
new_dict = merge_two_dicts(sign, power, var1, var2,
|
|
853
|
+
all_variables[var1],
|
|
854
|
+
all_variables[var2])
|
|
855
|
+
for var in new_dict:
|
|
856
|
+
all_variables[var] = new_dict
|
|
857
|
+
|
|
858
|
+
result = {}
|
|
859
|
+
|
|
860
|
+
for variable, variable_dict in all_variables.items():
|
|
861
|
+
if variable not in result:
|
|
862
|
+
vars = list(variable_dict.keys())
|
|
863
|
+
if 1 in vars:
|
|
864
|
+
canonical_rep = 1
|
|
865
|
+
else:
|
|
866
|
+
vars.sort()
|
|
867
|
+
canonical_rep = vars[0]
|
|
868
|
+
|
|
869
|
+
canonical_rep_sign, canonical_rep_power = (
|
|
870
|
+
variable_dict[canonical_rep])
|
|
871
|
+
|
|
872
|
+
for (var, (sign, power)) in variable_dict.items():
|
|
873
|
+
result[var] = (canonical_rep_sign * sign,
|
|
874
|
+
canonical_rep_power - power,
|
|
875
|
+
canonical_rep)
|
|
876
|
+
|
|
877
|
+
return result
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
def _canonical_representative_to_polynomial_substituition(
|
|
881
|
+
canonical_representative, order_of_u):
|
|
882
|
+
|
|
883
|
+
result = {}
|
|
884
|
+
|
|
885
|
+
for var1, signed_var2 in canonical_representative.items():
|
|
886
|
+
sign, power, var2 = signed_var2
|
|
887
|
+
if not var1 == var2:
|
|
888
|
+
|
|
889
|
+
if order_of_u == 2:
|
|
890
|
+
u = Polynomial.constant_polynomial(-1)
|
|
891
|
+
else:
|
|
892
|
+
u = Polynomial.from_variable_name('u')
|
|
893
|
+
|
|
894
|
+
sign_and_power = (
|
|
895
|
+
Polynomial.constant_polynomial(sign) *
|
|
896
|
+
u ** (power % order_of_u))
|
|
897
|
+
|
|
898
|
+
if var2 == 1:
|
|
899
|
+
result[var1] = sign_and_power
|
|
900
|
+
else:
|
|
901
|
+
result[var1] = (sign_and_power *
|
|
902
|
+
Polynomial.from_variable_name(var2))
|
|
903
|
+
|
|
904
|
+
return result
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
def _retrieve_url(url):
|
|
908
|
+
|
|
909
|
+
overview_url = "https://ptolemy.unhyperbolic.org/data/overview.html"
|
|
910
|
+
|
|
911
|
+
try:
|
|
912
|
+
# Remember SnapPy's SIGALRM handler (defined in app.py)
|
|
913
|
+
# And temporarily disable it (except under windows which does not
|
|
914
|
+
# have SIGALRM)
|
|
915
|
+
sigalrm_handler = None
|
|
916
|
+
if hasattr(signal, 'SIGALRM'):
|
|
917
|
+
sigalrm_handler = signal.signal(signal.SIGALRM, signal.SIG_IGN)
|
|
918
|
+
r = Request(url,
|
|
919
|
+
headers={'User-Agent': 'Wget/1.20.3'})
|
|
920
|
+
s = urlopen(r)
|
|
921
|
+
|
|
922
|
+
except HTTPError as e:
|
|
923
|
+
if e.code in [404, 406]:
|
|
924
|
+
raise PtolemyFileMissingError(
|
|
925
|
+
"The ptolemy variety has probably not been computed "
|
|
926
|
+
"yet, see %s (%s)" % (overview_url, e))
|
|
927
|
+
else:
|
|
928
|
+
raise PtolemyFileMissingError(
|
|
929
|
+
"The ptolemy variety has probably not been computed "
|
|
930
|
+
"yet or the given data_url or environment variable "
|
|
931
|
+
"PTOLEMY_DATA_URL "
|
|
932
|
+
"is not configured correctly: %s. Also see %s" % (
|
|
933
|
+
e, overview_url))
|
|
934
|
+
|
|
935
|
+
except OSError as e:
|
|
936
|
+
# IOError: this means the file wasn't there or we couldn't connect
|
|
937
|
+
# to the server
|
|
938
|
+
if url.startswith('http:') or url.startswith('https'):
|
|
939
|
+
# IOError for http means we could not connect to server
|
|
940
|
+
raise RuntimeError(
|
|
941
|
+
"Problem connecting to server while retrieving %s: "
|
|
942
|
+
"%s" % (url, e))
|
|
943
|
+
else:
|
|
944
|
+
# Otherwise, it probably means the file wasn't there
|
|
945
|
+
raise PtolemyFileMissingError(
|
|
946
|
+
"The ptolemy variety has probably not been computed "
|
|
947
|
+
"yet or the given data_url or environment variable "
|
|
948
|
+
"PTOLEMY_DATA_URL "
|
|
949
|
+
"is not configured correctly: %s. Also see %s" % (
|
|
950
|
+
e, overview_url))
|
|
951
|
+
finally:
|
|
952
|
+
# Always restore the original signal handler
|
|
953
|
+
if sigalrm_handler: # Not supported under windows
|
|
954
|
+
signal.signal(signal.SIGALRM, sigalrm_handler)
|
|
955
|
+
|
|
956
|
+
text = s.read()
|
|
957
|
+
|
|
958
|
+
if url.endswith('.gz'):
|
|
959
|
+
import gzip
|
|
960
|
+
text = gzip.decompress(text)
|
|
961
|
+
|
|
962
|
+
# Read the text
|
|
963
|
+
text = text.decode('ascii').replace('\r\n', '\n')
|
|
964
|
+
|
|
965
|
+
if not (url.startswith('http:') or url.startswith('https')):
|
|
966
|
+
# If this is a normal file, we are done
|
|
967
|
+
return text
|
|
968
|
+
|
|
969
|
+
# For http, we need to check that this isn't an error message
|
|
970
|
+
# by checking the HTTP code
|
|
971
|
+
code = s.getcode()
|
|
972
|
+
if code == 200:
|
|
973
|
+
# HTTP code 200 means alright
|
|
974
|
+
return text
|
|
975
|
+
|
|
976
|
+
# Otherwise we have an error
|
|
977
|
+
httpErr = "(HTTP Error %d while accessing %s)" % (code, url)
|
|
978
|
+
|
|
979
|
+
if code in [404, 406]:
|
|
980
|
+
# 404 means file not found
|
|
981
|
+
raise PtolemyFileMissingError(
|
|
982
|
+
"The ptolemy variety has probably not been computed "
|
|
983
|
+
"yet, see %s (%s)" % (overview_url, httpErr))
|
|
984
|
+
|
|
985
|
+
# Everything else means something is wrong with the server
|
|
986
|
+
# configuration or the connection to the server
|
|
987
|
+
raise RuntimeError(
|
|
988
|
+
"Problem retrieving file from server, please report to "
|
|
989
|
+
"enischte@gmail.com: %s" % httpErr)
|
|
990
|
+
|
|
991
|
+
@sage_method
|
|
992
|
+
def _sage_ideal(vars, polynomials, order='lex'):
|
|
993
|
+
polynomialRing = PolynomialRing(RationalField(), vars, order=order)
|
|
994
|
+
|
|
995
|
+
return Ideal(polynomialRing, [ p.sage() for p in polynomials ])
|