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,236 @@
|
|
|
1
|
+
from ...sage_helper import _within_sage
|
|
2
|
+
if _within_sage:
|
|
3
|
+
from ...sage_helper import (ZZ, QQ, GF, PolynomialRing, LaurentPolynomialRing,
|
|
4
|
+
CyclotomicField, vector, matrix, is_power_of_two,
|
|
5
|
+
identity_matrix, block_matrix, gcd,
|
|
6
|
+
VectorSpace, MatrixSpace, ChainComplex,
|
|
7
|
+
prime_range, prime_powers)
|
|
8
|
+
|
|
9
|
+
from ..nsagetools import (MapToFreeAbelianization,
|
|
10
|
+
compute_torsion,
|
|
11
|
+
fox_derivative_with_involution,
|
|
12
|
+
fox_derivative,
|
|
13
|
+
fast_determinant_of_laurent_poly_matrix,
|
|
14
|
+
last_square_submatrix,
|
|
15
|
+
first_square_submatrix)
|
|
16
|
+
|
|
17
|
+
def print_function(verbose, indent=0):
|
|
18
|
+
def answer(*args, **kwargs):
|
|
19
|
+
if verbose:
|
|
20
|
+
print((indent - 1)*' ', *args, **kwargs)
|
|
21
|
+
return answer
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def homology_of_cyclic_branched_cover(knot_exterior, p):
|
|
25
|
+
C = knot_exterior.covers(p, cover_type='cyclic')[0]
|
|
26
|
+
return [d for d in C.homology().elementary_divisors() if d != 0]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def primes_appearing(knot_exterior, p):
|
|
30
|
+
"""
|
|
31
|
+
sage: M = Manifold('K12n731')
|
|
32
|
+
sage: primes_appearing(M, 3)
|
|
33
|
+
[2, 13]
|
|
34
|
+
"""
|
|
35
|
+
C = knot_exterior.covers(p, cover_type='cyclic')[0]
|
|
36
|
+
divisors = C.homology().elementary_divisors()
|
|
37
|
+
primes = set()
|
|
38
|
+
for d in divisors:
|
|
39
|
+
if d != 0:
|
|
40
|
+
primes.update([p for p, e in ZZ(d).factor()])
|
|
41
|
+
return sorted(primes)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def nonzero_divisor_product(knot_exterior, p):
|
|
45
|
+
"""
|
|
46
|
+
sage: M = Manifold('K12n731')
|
|
47
|
+
sage: nonzero_divisor_product(M, 3)
|
|
48
|
+
2704
|
|
49
|
+
"""
|
|
50
|
+
C = knot_exterior.covers(p, cover_type='cyclic')[0]
|
|
51
|
+
divisors = C.homology().elementary_divisors()
|
|
52
|
+
ans = 1
|
|
53
|
+
for d in divisors:
|
|
54
|
+
if d != 0:
|
|
55
|
+
ans *= d
|
|
56
|
+
return ans
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MatrixRepresentation():
|
|
60
|
+
"""
|
|
61
|
+
A representation from a finitely-presented group to GL(n, R),
|
|
62
|
+
where R is a ring::
|
|
63
|
+
|
|
64
|
+
sage: MatSp = MatrixSpace(ZZ, 2)
|
|
65
|
+
sage: S = MatSp([[0, -1], [1, 0]])
|
|
66
|
+
sage: T = MatSp([[1, 1], [0, 1]])
|
|
67
|
+
sage: rho = MatrixRepresentation(['s', 't'], [6*'st'], MatSp, [S, T])
|
|
68
|
+
sage: rho
|
|
69
|
+
<MatRep from G(st) to GL(2, Integer Ring)>
|
|
70
|
+
sage: rho(2*'s') == rho(3*'st') == -identity_matrix(2)
|
|
71
|
+
True
|
|
72
|
+
sage: rho('ttsTTTsTTsTTstss')
|
|
73
|
+
[17 29]
|
|
74
|
+
[ 7 12]
|
|
75
|
+
"""
|
|
76
|
+
def __init__(self, generators, relators, image_ring, matrices):
|
|
77
|
+
if isinstance(matrices, dict):
|
|
78
|
+
images = matrices
|
|
79
|
+
all_gens = list(generators) + [g.swapcase() for g in generators]
|
|
80
|
+
assert set(matrices) == set(all_gens)
|
|
81
|
+
else:
|
|
82
|
+
assert len(generators) == len(matrices)
|
|
83
|
+
images = {}
|
|
84
|
+
for g, m in zip(generators, matrices):
|
|
85
|
+
images[g] = m
|
|
86
|
+
images[g.swapcase()] = image_ring(m.inverse())
|
|
87
|
+
|
|
88
|
+
self.images = images
|
|
89
|
+
self.image_ring = image_ring
|
|
90
|
+
self.base_ring = self.image_ring.base_ring()
|
|
91
|
+
self.dim = self.image_ring.ncols()
|
|
92
|
+
self.generators = generators
|
|
93
|
+
self.relators = relators
|
|
94
|
+
assert all(m.parent() == self.image_ring for m in images.values())
|
|
95
|
+
self._check_rep()
|
|
96
|
+
|
|
97
|
+
def _check_rep(self):
|
|
98
|
+
assert all(self(g + g.swapcase()) == 1 for g in self.generators)
|
|
99
|
+
assert all(self(rel) == 1 for rel in self.relators)
|
|
100
|
+
|
|
101
|
+
def range(self):
|
|
102
|
+
return self.image_ring
|
|
103
|
+
|
|
104
|
+
def __call__(self, word):
|
|
105
|
+
ans = self.image_ring(1)
|
|
106
|
+
for w in word:
|
|
107
|
+
ans = ans * self.images[w]
|
|
108
|
+
return ans
|
|
109
|
+
|
|
110
|
+
def __repr__(self):
|
|
111
|
+
gens = ''.join(self.generators)
|
|
112
|
+
return '<MatRep from G(' + gens + ') to GL(%s, %s)>' % (self.dim, self.base_ring)
|
|
113
|
+
|
|
114
|
+
def twisted_chain_complex(self):
|
|
115
|
+
"""
|
|
116
|
+
Returns chain complex of the presentation CW complex of the
|
|
117
|
+
given group with coefficients twisted by self.
|
|
118
|
+
"""
|
|
119
|
+
gens, rels, rho = self.generators, self.relators, self
|
|
120
|
+
d2 = [ [fox_derivative_with_involution(R, rho, g) for R in rels] for g in gens]
|
|
121
|
+
d2 = block_matrix(d2, nrows=len(gens), ncols=len(rels))
|
|
122
|
+
d1 = [rho(g.swapcase()) - 1 for g in gens]
|
|
123
|
+
d1 = block_matrix(d1, nrows=1, ncols=len(gens))
|
|
124
|
+
C = ChainComplex({1:d1, 2:d2}, degree_of_differential=-1, check=True)
|
|
125
|
+
return C
|
|
126
|
+
|
|
127
|
+
def twisted_cochain_complex(self):
|
|
128
|
+
"""
|
|
129
|
+
Returns the cochain complex of the presentation CW complex of the
|
|
130
|
+
given group with coefficients twisted by self.
|
|
131
|
+
"""
|
|
132
|
+
gens, rels, rho = self.generators, self.relators, self
|
|
133
|
+
d1 = [[fox_derivative(R, rho, g) for g in gens] for R in rels]
|
|
134
|
+
d1 = block_matrix(d1, nrows=len(rels), ncols=len(gens))
|
|
135
|
+
d0 = [rho(g) - 1 for g in gens]
|
|
136
|
+
d0 = block_matrix(d0, nrow=len(gens), ncols=1)
|
|
137
|
+
C = ChainComplex({0:d0, 1:d1}, check=True)
|
|
138
|
+
return C
|
|
139
|
+
|
|
140
|
+
def semidirect_rep_from_twisted_cocycle(self, cocycle):
|
|
141
|
+
"""
|
|
142
|
+
Given a representation rho to GL(R, n) and a rho-twisted
|
|
143
|
+
1-cocycle, construct the representation to GL(R, n + 1)
|
|
144
|
+
corresponding to the semidirect product.
|
|
145
|
+
|
|
146
|
+
Note: Since we prefer to stick to left-actions only, unlike [HLK],
|
|
147
|
+
this is the semidirect product associated to the left action of
|
|
148
|
+
GL(R, n) on V = R^n. That is, pairs (v, A) with v in V and A in
|
|
149
|
+
GL(R, n) where (v, A) * (w, B) = (v + A*w, A*B)::
|
|
150
|
+
|
|
151
|
+
sage: MatSp = MatrixSpace(GF(5), 2)
|
|
152
|
+
sage: A, I = MatSp([[0, 4], [1, 4]]), MatSp(1)
|
|
153
|
+
sage: G = Manifold('K12a169').fundamental_group()
|
|
154
|
+
sage: rho = MatrixRepresentation(G.generators(), G.relators(), MatSp, [A, I])
|
|
155
|
+
sage: cocycle = vector(GF(5), (0, 0, 1, 0))
|
|
156
|
+
sage: rho_til = rho.semidirect_rep_from_twisted_cocycle(cocycle)
|
|
157
|
+
sage: rho_til('abAB')
|
|
158
|
+
[1 0 4]
|
|
159
|
+
[0 1 1]
|
|
160
|
+
[0 0 1]
|
|
161
|
+
|
|
162
|
+
Note: rho here is rep_theory.cyclic_rep(G, A)
|
|
163
|
+
"""
|
|
164
|
+
gens, rels, rho = self.generators, self.relators, self
|
|
165
|
+
n = rho.dim
|
|
166
|
+
assert len(cocycle) == len(gens)*n
|
|
167
|
+
new_mats = []
|
|
168
|
+
for i, g in enumerate(gens):
|
|
169
|
+
v = matrix([cocycle[i*n:(i+1)*n]]).transpose()
|
|
170
|
+
zeros = matrix(n*[0])
|
|
171
|
+
one = matrix([[1]])
|
|
172
|
+
A = block_matrix([[rho(g), v], [zeros, one]])
|
|
173
|
+
new_mats.append(A)
|
|
174
|
+
|
|
175
|
+
target = MatrixSpace(rho.base_ring, n + 1)
|
|
176
|
+
return MatrixRepresentation(gens, rels, target, new_mats)
|
|
177
|
+
|
|
178
|
+
# ----- end class MatrixRepresentation --------------------------------
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def normalize_polynomial(f):
|
|
184
|
+
"""
|
|
185
|
+
Multiply by t^-n so that the constant term is nonzero.
|
|
186
|
+
|
|
187
|
+
sage: t = PolynomialRing(ZZ, 't').gen()
|
|
188
|
+
sage: normalize_polynomial(t**3 + 2*t**2)
|
|
189
|
+
t + 2
|
|
190
|
+
"""
|
|
191
|
+
e = min(f.exponents())
|
|
192
|
+
t = f.parent().gen()
|
|
193
|
+
return f // t**e
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def twisted_alexander_polynomial(alpha, reduced=False):
|
|
197
|
+
"""
|
|
198
|
+
In [HKL], alpha is epsilon x rho; in nsagetools, it would be called
|
|
199
|
+
phialpha with phi being epsilon. If reduced is True, the answer is
|
|
200
|
+
divided by (t - 1).
|
|
201
|
+
"""
|
|
202
|
+
F = alpha('a').base_ring().base_ring()
|
|
203
|
+
epsilon = alpha.epsilon
|
|
204
|
+
gens, rels = alpha.generators, alpha.relators
|
|
205
|
+
k = len(gens)
|
|
206
|
+
|
|
207
|
+
# Make sure this special algorithm applies.
|
|
208
|
+
assert len(rels) == len(gens) - 1 and epsilon.range().rank() == 1
|
|
209
|
+
|
|
210
|
+
# Want the first variable to be homologically nontrivial
|
|
211
|
+
i0 = next(i for i, g in enumerate(gens) if epsilon(g) != 0)
|
|
212
|
+
gens = gens[i0:] + gens[:i0]
|
|
213
|
+
|
|
214
|
+
# Boundary maps for chain complex
|
|
215
|
+
|
|
216
|
+
d2 = [ [fox_derivative_with_involution(R, alpha, g) for R in rels] for g in gens]
|
|
217
|
+
d2 = block_matrix(d2, nrows=k, ncols=k-1)
|
|
218
|
+
d1 = [alpha(g.swapcase()) - 1 for g in gens]
|
|
219
|
+
d1 = block_matrix(d1, nrows=1, ncols=k)
|
|
220
|
+
assert d1 * d2 == 0
|
|
221
|
+
|
|
222
|
+
T = last_square_submatrix(d2)
|
|
223
|
+
B = first_square_submatrix(d1)
|
|
224
|
+
|
|
225
|
+
T = normalize_polynomial(fast_determinant_of_laurent_poly_matrix(T))
|
|
226
|
+
B = normalize_polynomial(fast_determinant_of_laurent_poly_matrix(B))
|
|
227
|
+
|
|
228
|
+
q, r = T.quo_rem(B)
|
|
229
|
+
assert r == 0
|
|
230
|
+
ans = normalize_polynomial(q)
|
|
231
|
+
if reduced:
|
|
232
|
+
t = ans.parent().gen()
|
|
233
|
+
ans, r = ans.quo_rem(t - 1)
|
|
234
|
+
assert r == 0
|
|
235
|
+
return ans
|
|
236
|
+
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Here, we take a different approach towards computing the HKL
|
|
3
|
+
topological slice obstructions, which in particular allows us to
|
|
4
|
+
consider characters to Z/(q^e Z) where e > 1.
|
|
5
|
+
|
|
6
|
+
This code corresponds to Section 3.20 of [DG].
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from ...sage_helper import _within_sage, sage_method
|
|
10
|
+
if _within_sage:
|
|
11
|
+
from ...sage_helper import (gcd, gap, ZZ, is_prime, is_prime_power,
|
|
12
|
+
CyclotomicField, MatrixSpace,
|
|
13
|
+
LaurentPolynomialRing)
|
|
14
|
+
|
|
15
|
+
from ..nsagetools import MapToFreeAbelianization
|
|
16
|
+
from .basics import (MatrixRepresentation,
|
|
17
|
+
primes_appearing,
|
|
18
|
+
homology_of_cyclic_branched_cover,
|
|
19
|
+
twisted_alexander_polynomial,
|
|
20
|
+
print_function)
|
|
21
|
+
|
|
22
|
+
from .poly_norm import (poly_is_a_norm,
|
|
23
|
+
poly_is_a_norm_in_some_extension)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def abelian_p_group_as_gap_polycyclic(p, invariants):
|
|
27
|
+
assert all(q % p == 0 for q in invariants)
|
|
28
|
+
facs = [gap.CyclicGroup(q) for q in invariants]
|
|
29
|
+
G = gap.DirectProduct(facs)
|
|
30
|
+
return G.IsomorphismSpecialPcGroup().Image()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def possible_metabolizers(abelian_p_group):
|
|
34
|
+
G = abelian_p_group
|
|
35
|
+
gap.eval("IsNotFail := function(ans) return ans <> fail; end;")
|
|
36
|
+
order = ZZ(G.Order())
|
|
37
|
+
facs = order.factor()
|
|
38
|
+
assert len(facs) == 1
|
|
39
|
+
p, n = facs[0]
|
|
40
|
+
assert n % 2 == 0
|
|
41
|
+
target = p**(n//2)
|
|
42
|
+
ans = []
|
|
43
|
+
for S in G.NormalSubgroups():
|
|
44
|
+
if S.Order() == target:
|
|
45
|
+
Q = (G/S).IsomorphismSpecialPcGroup().Image()
|
|
46
|
+
R = S.IsomorphismSpecialPcGroup().Image()
|
|
47
|
+
if Q.IsomorphismGroups(R).IsNotFail():
|
|
48
|
+
ans.append(S)
|
|
49
|
+
return ans
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def maximal_abelian_p_quotient(gap_fp_group, p):
|
|
53
|
+
G = gap_fp_group
|
|
54
|
+
ab_quo = G.MaximalAbelianQuotient()
|
|
55
|
+
iso1 = ab_quo.Image().IsomorphismSpecialPcGroup()
|
|
56
|
+
G_ab = iso1.Image()
|
|
57
|
+
C = G_ab.SylowComplement(p)
|
|
58
|
+
p_quo = G_ab.NaturalHomomorphismByNormalSubgroup(C)
|
|
59
|
+
iso2 = p_quo.Image().IsomorphismSpecialPcGroup()
|
|
60
|
+
# GAP does composition as though function act on the right
|
|
61
|
+
return ab_quo * iso1 * p_quo * iso2
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def power_appearing(n, p):
|
|
65
|
+
n, p = ZZ(n), ZZ(p)
|
|
66
|
+
assert is_prime(p)
|
|
67
|
+
if n == 0:
|
|
68
|
+
return 0
|
|
69
|
+
ans = 0
|
|
70
|
+
while n % p == 0:
|
|
71
|
+
ans += 1
|
|
72
|
+
n = n // p
|
|
73
|
+
return ans
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def order_of_p_part_of_homology(manifold, p):
|
|
77
|
+
assert is_prime(p)
|
|
78
|
+
invariants = manifold.homology().elementary_divisors()
|
|
79
|
+
e = sum(power_appearing(d, p) for d in invariants)
|
|
80
|
+
return p**e
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def in_kernel(gap_hom, subgroup):
|
|
84
|
+
return all(gap_hom.Image(g).IsOne()
|
|
85
|
+
for g in subgroup.GeneratorsOfGroup())
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def rep_from_cyclic_quotient(snappy_group, quotient_group, images):
|
|
89
|
+
C = quotient_group
|
|
90
|
+
G = snappy_group
|
|
91
|
+
K = CyclotomicField(C.Order(), 'z')
|
|
92
|
+
z = K.gen()
|
|
93
|
+
R = LaurentPolynomialRing(K, 't')
|
|
94
|
+
t = R.gen()
|
|
95
|
+
MatSp = MatrixSpace(R, 1)
|
|
96
|
+
|
|
97
|
+
f1 = C.GeneratorsOfGroup()[1]
|
|
98
|
+
assert f1.Order() == C.Order()
|
|
99
|
+
|
|
100
|
+
def to_cyc_field(elt):
|
|
101
|
+
for e in range(int(C.Order())):
|
|
102
|
+
if elt == f1**e:
|
|
103
|
+
return z**e
|
|
104
|
+
|
|
105
|
+
epsilon = MapToFreeAbelianization(G)
|
|
106
|
+
gens, rels = G.generators(), G.relators()
|
|
107
|
+
final_images = [MatSp(t**(epsilon(g)[0]) * to_cyc_field(m))
|
|
108
|
+
for g, m in zip(gens, images)]
|
|
109
|
+
alpha = MatrixRepresentation(gens, rels, MatSp, final_images)
|
|
110
|
+
alpha.epsilon = epsilon
|
|
111
|
+
return alpha
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def gap_group_with_meridian_killed(G):
|
|
115
|
+
meridian = []
|
|
116
|
+
for x in G.meridian():
|
|
117
|
+
if x.islower():
|
|
118
|
+
meridian.append(x)
|
|
119
|
+
else:
|
|
120
|
+
meridian.append(x.lower() + '^-1')
|
|
121
|
+
meridian = '*'.join(meridian)
|
|
122
|
+
|
|
123
|
+
gap_str = G.gap_string()
|
|
124
|
+
tail = ']; end,[])'
|
|
125
|
+
assert gap_str.endswith(tail)
|
|
126
|
+
gap_str = gap_str.replace(tail, ', ' + meridian + tail)
|
|
127
|
+
return gap(gap_str)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def slicing_obstructed_by_larger_quotient(knot_exterior, p, q,
|
|
131
|
+
ribbon_mode=False, verbose=False):
|
|
132
|
+
"""
|
|
133
|
+
Here, we take a different approach towards computing the HKL
|
|
134
|
+
topological slice obstructions, which in particular allows us to
|
|
135
|
+
consider characters to Z/(q^e Z) where e > 1.
|
|
136
|
+
|
|
137
|
+
We forgo the representation theory and work directly with the cyclic
|
|
138
|
+
(branched) covers themselves. This amounts to using the original
|
|
139
|
+
theorem in Kirk-Livingston 1999.
|
|
140
|
+
|
|
141
|
+
We cut down the number of possible metabolizers via Sawin's
|
|
142
|
+
observation that if M is a metabolizer of an abelian p-group H with
|
|
143
|
+
respect to a nondegenerate bilinear form, then H/M is isomorphic to M.
|
|
144
|
+
|
|
145
|
+
See Section 3.20 of [DG] for details::
|
|
146
|
+
|
|
147
|
+
sage: M = Manifold('16n192088')
|
|
148
|
+
sage: slicing_obstructed_by_larger_quotient(M, 2, 3, verbose=True)
|
|
149
|
+
Homology: [ 81 ]
|
|
150
|
+
Candidate metabolizers: 1
|
|
151
|
+
Considing cyclic quotients up to size 3^2
|
|
152
|
+
Looking at Z/3^1 with 1 remaining
|
|
153
|
+
Looking at Z/3^2 with 1 remaining
|
|
154
|
+
Now with 0 remaining
|
|
155
|
+
True
|
|
156
|
+
|
|
157
|
+
Note: This code requires GAP, which is standard in SageMath.
|
|
158
|
+
"""
|
|
159
|
+
print = print_function(verbose, indent=8)
|
|
160
|
+
M = knot_exterior.copy()
|
|
161
|
+
assert M.num_cusps() == 1
|
|
162
|
+
assert is_prime_power(p) and is_prime(q)
|
|
163
|
+
M.dehn_fill((p, 0))
|
|
164
|
+
covers = M.covers(p, cover_type='cyclic')
|
|
165
|
+
assert len(covers) == 1
|
|
166
|
+
cover = covers[0]
|
|
167
|
+
H_q_size = order_of_p_part_of_homology(cover, q)
|
|
168
|
+
if H_q_size == 1:
|
|
169
|
+
return False
|
|
170
|
+
cover.dehn_fill((0, 0))
|
|
171
|
+
G = cover.fundamental_group()
|
|
172
|
+
Gbar = gap_group_with_meridian_killed(G)
|
|
173
|
+
quo_q = maximal_abelian_p_quotient(Gbar, q)
|
|
174
|
+
H_q = quo_q.Image()
|
|
175
|
+
assert H_q_size == H_q.Order()
|
|
176
|
+
print(f'Homology: {H_q.AbelianInvariants()}')
|
|
177
|
+
metas = possible_metabolizers(H_q)
|
|
178
|
+
print(f'Candidate metabolizers: {len(metas)}')
|
|
179
|
+
n = max(power_appearing(M.Exponent(), q) for M in metas)
|
|
180
|
+
print(f'Considing cyclic quotients up to size {q}^{n}')
|
|
181
|
+
|
|
182
|
+
remaining_metas = set(range(len(metas))) # recorded by index
|
|
183
|
+
for e in range(1, n + 1):
|
|
184
|
+
if not remaining_metas:
|
|
185
|
+
break
|
|
186
|
+
|
|
187
|
+
print(4*' ' + f'Looking at Z/{q}^{e} with {len(remaining_metas)} remaining')
|
|
188
|
+
C = gap.CyclicGroup(q**e)
|
|
189
|
+
cyclic_quos = H_q.GQuotients(C)
|
|
190
|
+
|
|
191
|
+
# We sort the cyclic_quotients by how many metas they would each rule out.
|
|
192
|
+
would_eliminate = []
|
|
193
|
+
for f in cyclic_quos:
|
|
194
|
+
new_obs = {i for i, M in enumerate(metas)
|
|
195
|
+
if i in remaining_metas and in_kernel(f, M)}
|
|
196
|
+
if new_obs:
|
|
197
|
+
would_eliminate.append((f, new_obs))
|
|
198
|
+
|
|
199
|
+
would_eliminate.sort(key=lambda x:len(x[1]), reverse=True)
|
|
200
|
+
|
|
201
|
+
# Now compute the twisted alexander polynomials
|
|
202
|
+
for f, obs in would_eliminate:
|
|
203
|
+
if len(remaining_metas & obs):
|
|
204
|
+
images = [f.Image(quo_q.Image(g)) for g in Gbar.GeneratorsOfGroup()]
|
|
205
|
+
alpha = rep_from_cyclic_quotient(G, C, images)
|
|
206
|
+
alex = twisted_alexander_polynomial(alpha, reduced=True)
|
|
207
|
+
if ribbon_mode or q != 2:
|
|
208
|
+
norm = poly_is_a_norm(alex)
|
|
209
|
+
else:
|
|
210
|
+
norm = poly_is_a_norm_in_some_extension(alex)
|
|
211
|
+
if not norm:
|
|
212
|
+
remaining_metas = remaining_metas - obs
|
|
213
|
+
print(8*' ' + f'Now with {len(remaining_metas)} remaining')
|
|
214
|
+
if not remaining_metas:
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
return len(remaining_metas) == 0
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Determining when a polynomial whose coefficients lie in a
|
|
4
|
+
CyclotomicField is a norm.
|
|
5
|
+
|
|
6
|
+
Uses the method of Sections 3.9 and 3.11 of [DG].
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from ...sage_helper import _within_sage, sage_method
|
|
12
|
+
if _within_sage:
|
|
13
|
+
from ...sage_helper import (QQ, PolynomialRing, CyclotomicField)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def poly_involution(f):
|
|
17
|
+
"""
|
|
18
|
+
sage: K = CyclotomicField(3, 'z')
|
|
19
|
+
sage: R = PolynomialRing(K, 't')
|
|
20
|
+
sage: z, t = K.gen(), R.gen()
|
|
21
|
+
sage: poly_involution(z*t**2 + (1/z)*t + 1)
|
|
22
|
+
t^2 + z*t - z - 1
|
|
23
|
+
"""
|
|
24
|
+
R = f.parent()
|
|
25
|
+
t = R.gen()
|
|
26
|
+
K = R.base_ring()
|
|
27
|
+
if K.is_finite():
|
|
28
|
+
n = K.degree()
|
|
29
|
+
assert n % 2 == 0
|
|
30
|
+
bar = K.galois_group().gen()**(n/2)
|
|
31
|
+
else:
|
|
32
|
+
z = K.gen()
|
|
33
|
+
bar = K.hom([1/z])
|
|
34
|
+
ans = R(0)
|
|
35
|
+
d = f.degree()
|
|
36
|
+
for e in f.exponents():
|
|
37
|
+
ans += bar(f[e])*t**(d - e)
|
|
38
|
+
return ans
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def poly_is_a_norm(g):
|
|
42
|
+
"""
|
|
43
|
+
Return whether a symmetric polynomial g(t) over a CyclotomicField is
|
|
44
|
+
equal to (const) f(t) fbar(t) where fbar is poly_involution(f)::
|
|
45
|
+
|
|
46
|
+
sage: K = CyclotomicField(5, 'z')
|
|
47
|
+
sage: R = PolynomialRing(K, 't')
|
|
48
|
+
sage: z, t = K.gen(), R.gen()
|
|
49
|
+
sage: f = z*t**2 + (1/z)*t + 1
|
|
50
|
+
sage: fbar = poly_involution(f)
|
|
51
|
+
sage: poly_is_a_norm(z**2 * f * fbar * (t - 1)**2)
|
|
52
|
+
True
|
|
53
|
+
sage: poly_is_a_norm(f**2 * fbar)
|
|
54
|
+
False
|
|
55
|
+
sage: poly_is_a_norm(f * fbar * (t - 1))
|
|
56
|
+
False
|
|
57
|
+
sage: poly_is_a_norm(4*t**2 + (z**3 + z**2 + 5)*t + 4)
|
|
58
|
+
False
|
|
59
|
+
"""
|
|
60
|
+
factors = dict(g.factor())
|
|
61
|
+
for h in factors:
|
|
62
|
+
assert h.is_monic()
|
|
63
|
+
hbar = poly_involution(h)
|
|
64
|
+
hbar = hbar/hbar.leading_coefficient()
|
|
65
|
+
if hbar == h and factors[h] % 2 != 0:
|
|
66
|
+
return False
|
|
67
|
+
elif factors[h] != factors[hbar]:
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
###########################################################################
|
|
74
|
+
#
|
|
75
|
+
# Dealing with F_2-homology as in Section 3.11 of [DG].
|
|
76
|
+
#
|
|
77
|
+
###########################################################################
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# This code was used to generate the `universal_degree_bound` but GAP
|
|
81
|
+
# is invoked in this file.
|
|
82
|
+
|
|
83
|
+
gap_code = \
|
|
84
|
+
"""
|
|
85
|
+
IsPowerOfTwo := function(n)
|
|
86
|
+
return 2^PValuation(n, 2) = n;
|
|
87
|
+
end;
|
|
88
|
+
|
|
89
|
+
# Given a subgroup H of G, checks if
|
|
90
|
+
#
|
|
91
|
+
# a) H is normal in G
|
|
92
|
+
# b) G/H is Z/2^k Z or Z/2 + Z/2^(k - 1)
|
|
93
|
+
#
|
|
94
|
+
# If so, it returns k; otherwise, it returns 0.
|
|
95
|
+
|
|
96
|
+
QuotientAbelianOfSpecialType := function(G, H)
|
|
97
|
+
local Q, ab;
|
|
98
|
+
if IsPowerOfTwo(Index(G, H)) and IsNormal(G, H) then
|
|
99
|
+
ab := AbelianInvariants(G/H);
|
|
100
|
+
if Length(ab) = 1 then
|
|
101
|
+
return PValuation(ab[1], 2);
|
|
102
|
+
fi;
|
|
103
|
+
if Length(ab) = 2 and ab[1] = 2 then
|
|
104
|
+
return PValuation(ab[2], 2) + 1;
|
|
105
|
+
fi;
|
|
106
|
+
fi;
|
|
107
|
+
return 0;
|
|
108
|
+
end;
|
|
109
|
+
|
|
110
|
+
# For a Galois Group G, return the largest k so that there a normal H
|
|
111
|
+
# in G with [G:H] = 2^k and G/H is Z/2^k Z or Z/2 + Z/2^(k - 1)
|
|
112
|
+
|
|
113
|
+
DegreeBound := function(G)
|
|
114
|
+
local sgs;
|
|
115
|
+
sgs := List(ConjugacyClassesSubgroups(G), C -> Representative(C));
|
|
116
|
+
return Maximum(List(sgs, H -> QuotientAbelianOfSpecialType(G, H)));
|
|
117
|
+
end;
|
|
118
|
+
|
|
119
|
+
# This function computes a degree bound that works for any irreducible
|
|
120
|
+
# polynomial of degree n over *any* number field.
|
|
121
|
+
|
|
122
|
+
UniversalDegreeBound := function(degree)
|
|
123
|
+
return Maximum(List([1..NrTransitiveGroups(degree)],
|
|
124
|
+
k -> DegreeBound(TransitiveGroup(degree, k))));
|
|
125
|
+
end;
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
universal_degree_bound = dict([
|
|
129
|
+
[ 2, 1 ],
|
|
130
|
+
[ 4, 2 ],
|
|
131
|
+
[ 6, 2 ],
|
|
132
|
+
[ 8, 3 ],
|
|
133
|
+
[ 10, 3 ],
|
|
134
|
+
[ 12, 3 ],
|
|
135
|
+
[ 14, 2 ],
|
|
136
|
+
[ 16, 4 ],
|
|
137
|
+
[ 18, 4 ],
|
|
138
|
+
[ 20, 4 ],
|
|
139
|
+
[ 22, 2 ],
|
|
140
|
+
[ 24, 4 ],
|
|
141
|
+
[ 26, 3 ],
|
|
142
|
+
[ 28, 3 ],
|
|
143
|
+
[ 30, 4 ]])
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def size_split_field_intersect_cyclotomic(poly):
|
|
147
|
+
"""
|
|
148
|
+
Let G be the Galois group of the given irreducible polynomial. We
|
|
149
|
+
compute the largest size of G/H where:
|
|
150
|
+
|
|
151
|
+
1. H is normal in G, with [G:H] = 2^k.
|
|
152
|
+
|
|
153
|
+
2. G/H is abelian and either Z/2^k or Z/2 + Z/2^(k - 1).
|
|
154
|
+
|
|
155
|
+
The result is an upper bound on the degree d = 2^k over Q of the
|
|
156
|
+
intersection of the splitting field of the polynomial with
|
|
157
|
+
CyclotomicField(2^infinity). The number k is returned.
|
|
158
|
+
|
|
159
|
+
Note: Here we just return the universal degree bound. The
|
|
160
|
+
implementation used in [SG] computed the actual Galois group when
|
|
161
|
+
the field is QQ but this avoids a dependency on GAP.
|
|
162
|
+
"""
|
|
163
|
+
if poly.degree() <= 1:
|
|
164
|
+
return 0
|
|
165
|
+
|
|
166
|
+
return universal_degree_bound[poly.degree()]
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def poly_is_a_norm_in_some_extension(g):
|
|
170
|
+
"""
|
|
171
|
+
Given a symmetric polyomial over the rationals, return whether it
|
|
172
|
+
is a norm in *any* CyclotomicField(2**k, 'z')::
|
|
173
|
+
|
|
174
|
+
sage: t = PolynomialRing(QQ, 't').gen()
|
|
175
|
+
sage: f = (t - 1)*(t**2 - 3*t + 1)
|
|
176
|
+
sage: poly_is_a_norm_in_some_extension(f)
|
|
177
|
+
False
|
|
178
|
+
sage: f = (t**2 - t + 1)**2 * (t**2 - 3*t + 1)
|
|
179
|
+
sage: poly_is_a_norm_in_some_extension(f)
|
|
180
|
+
False
|
|
181
|
+
sage: f = t**4 + 4*t**2 + 1
|
|
182
|
+
sage: poly_is_a_norm_in_some_extension(f)
|
|
183
|
+
True
|
|
184
|
+
"""
|
|
185
|
+
K = g.parent().base_ring()
|
|
186
|
+
if K == QQ:
|
|
187
|
+
cyc_order = 1
|
|
188
|
+
else:
|
|
189
|
+
assert isinstance(K, type(CyclotomicField(4, 'z')))
|
|
190
|
+
cyc_order = K.degree() * 2
|
|
191
|
+
|
|
192
|
+
factors = dict(g.factor())
|
|
193
|
+
for h in factors:
|
|
194
|
+
assert h.is_monic()
|
|
195
|
+
hbar = poly_involution(h)
|
|
196
|
+
hbar = hbar/hbar.leading_coefficient()
|
|
197
|
+
if hbar == h:
|
|
198
|
+
if factors[h] % 2 == 0:
|
|
199
|
+
continue
|
|
200
|
+
else:
|
|
201
|
+
if h.degree() % 2 == 1: # any norm has even degree
|
|
202
|
+
return False
|
|
203
|
+
k = size_split_field_intersect_cyclotomic(h)
|
|
204
|
+
K = CyclotomicField(2**(cyc_order + k + 1), 'z')
|
|
205
|
+
if not poly_is_a_norm(h.change_ring(K)):
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
elif factors[h] != factors[hbar]:
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
return True
|
|
212
|
+
|