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,856 @@
|
|
|
1
|
+
from ..sage_helper import _within_sage, sage_method
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import operator
|
|
5
|
+
from fractions import Fraction
|
|
6
|
+
|
|
7
|
+
if _within_sage:
|
|
8
|
+
from ..sage_helper import prod
|
|
9
|
+
from sage.symbolic.ring import var as sage_var
|
|
10
|
+
|
|
11
|
+
#######################################################
|
|
12
|
+
# Public Definitions of Monomial and Polynomial class
|
|
13
|
+
|
|
14
|
+
# The coefficients of a polynomial can be any type, the
|
|
15
|
+
# policy for mixed coefficients is defined in
|
|
16
|
+
# _storage_type_policy and _operator_type_policy.
|
|
17
|
+
|
|
18
|
+
# Definition of Monomial Class
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Monomial():
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_variable_name(cls, var):
|
|
25
|
+
"""Construct a monomial with a single variable given as a string."""
|
|
26
|
+
assert isinstance(var, str)
|
|
27
|
+
return Monomial(1, ((var, 1),))
|
|
28
|
+
|
|
29
|
+
# Constructs a constant monomial
|
|
30
|
+
@classmethod
|
|
31
|
+
def constant_monomial(cls, coefficient):
|
|
32
|
+
return Monomial(coefficient, ())
|
|
33
|
+
|
|
34
|
+
# Constructor takes
|
|
35
|
+
# * a number type as coefficient
|
|
36
|
+
# * a list of pairs (variable_name, exponent) sorted by variable_name or
|
|
37
|
+
# a dictionary variable_name -> exponent
|
|
38
|
+
def __init__(self, coefficient, vars):
|
|
39
|
+
"""
|
|
40
|
+
>>> M = Monomial(2, (('a', 2), ('b', 3)))
|
|
41
|
+
>>> str(M)
|
|
42
|
+
'2 * a^2 * b^3'
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
self._coefficient = coefficient
|
|
46
|
+
|
|
47
|
+
if isinstance(vars, dict):
|
|
48
|
+
self._vars = _dict_to_ordered_tuple_of_pairs(vars)
|
|
49
|
+
else:
|
|
50
|
+
assert isinstance(vars, tuple)
|
|
51
|
+
for var, expo in vars:
|
|
52
|
+
assert isinstance(var, str)
|
|
53
|
+
assert isinstance(expo, int)
|
|
54
|
+
assert expo > 0
|
|
55
|
+
self._vars = vars
|
|
56
|
+
|
|
57
|
+
def __str__(self):
|
|
58
|
+
return self.to_string(
|
|
59
|
+
print_coefficient_method=default_print_coefficient_method,
|
|
60
|
+
force_print_sign=False)
|
|
61
|
+
|
|
62
|
+
__repr__ = __str__
|
|
63
|
+
|
|
64
|
+
def to_string(self, print_coefficient_method, force_print_sign):
|
|
65
|
+
"""
|
|
66
|
+
Print the polynomial. The print_coefficient_method is used to print the
|
|
67
|
+
coefficients. If force_print_sign is True, a sign is always included,
|
|
68
|
+
e.g., "+ 3 * x".
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
v = [var if expo == 1
|
|
72
|
+
else "%s^%s" % (var, expo)
|
|
73
|
+
for var, expo in self._vars]
|
|
74
|
+
|
|
75
|
+
coefficient_sign, coefficient_str = (
|
|
76
|
+
print_coefficient_method(self._coefficient))
|
|
77
|
+
|
|
78
|
+
if coefficient_str:
|
|
79
|
+
v = [coefficient_str] + v
|
|
80
|
+
if not v:
|
|
81
|
+
v = ["1"]
|
|
82
|
+
|
|
83
|
+
sign_less_str = " * ".join(v)
|
|
84
|
+
|
|
85
|
+
if force_print_sign or coefficient_sign == "-":
|
|
86
|
+
return coefficient_sign + " " + sign_less_str
|
|
87
|
+
|
|
88
|
+
return sign_less_str
|
|
89
|
+
|
|
90
|
+
def get_coefficient(self):
|
|
91
|
+
"""Return the coefficient."""
|
|
92
|
+
return self._coefficient
|
|
93
|
+
|
|
94
|
+
def coefficient_type(self):
|
|
95
|
+
"""Return the type of the coefficient."""
|
|
96
|
+
return type(self._coefficient)
|
|
97
|
+
|
|
98
|
+
def get_vars(self):
|
|
99
|
+
"""
|
|
100
|
+
Return a tuple of pairs (variable_name, exponent).
|
|
101
|
+
"""
|
|
102
|
+
return self._vars
|
|
103
|
+
|
|
104
|
+
def variables(self):
|
|
105
|
+
"""Return a list containing the variable names."""
|
|
106
|
+
return [var for var, expo in self._vars if expo > 0]
|
|
107
|
+
|
|
108
|
+
def degree(self, var=None):
|
|
109
|
+
"""Return the total degree of this monomial."""
|
|
110
|
+
return sum(this_degree
|
|
111
|
+
for this_var, this_degree in self._vars
|
|
112
|
+
if var is None or this_var == var)
|
|
113
|
+
|
|
114
|
+
def __mul__(self, other):
|
|
115
|
+
"""Multiply two monomials."""
|
|
116
|
+
|
|
117
|
+
assert isinstance(other, Monomial)
|
|
118
|
+
|
|
119
|
+
# Compute coefficient
|
|
120
|
+
coefficient = _operator_type_policy(
|
|
121
|
+
self._coefficient, other._coefficient, operator.mul)
|
|
122
|
+
|
|
123
|
+
# Compute the variables
|
|
124
|
+
var_dict = _combine_dicts(
|
|
125
|
+
[dict(self._vars), dict(other._vars)],
|
|
126
|
+
operator.add)
|
|
127
|
+
|
|
128
|
+
return Monomial(coefficient, var_dict)
|
|
129
|
+
|
|
130
|
+
def __pow__(self, other):
|
|
131
|
+
|
|
132
|
+
assert isinstance(other, int)
|
|
133
|
+
assert other >= 0
|
|
134
|
+
|
|
135
|
+
if other == 0:
|
|
136
|
+
return Monomial.constant_monomial(1)
|
|
137
|
+
if other == 1:
|
|
138
|
+
return self
|
|
139
|
+
if other % 2:
|
|
140
|
+
return self * (self ** (other - 1))
|
|
141
|
+
return (self * self) ** (other // 2)
|
|
142
|
+
|
|
143
|
+
def __neg__(self):
|
|
144
|
+
"""Negate this monomial."""
|
|
145
|
+
return Monomial(-self._coefficient, self._vars)
|
|
146
|
+
|
|
147
|
+
def __eq__(self, other):
|
|
148
|
+
"""Check whether two monomials are equal."""
|
|
149
|
+
|
|
150
|
+
assert isinstance(other, Monomial)
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
self._coefficient == other._coefficient and
|
|
154
|
+
self._vars == other._vars)
|
|
155
|
+
|
|
156
|
+
def convert_coefficient(self, conversion_function):
|
|
157
|
+
"""
|
|
158
|
+
Apply the specified conversion_function to the coefficient.
|
|
159
|
+
e.g. monomial.convert_coefficient(float)
|
|
160
|
+
"""
|
|
161
|
+
return Monomial(
|
|
162
|
+
conversion_function(self._coefficient),
|
|
163
|
+
self._vars)
|
|
164
|
+
|
|
165
|
+
def split_variable(self, variable):
|
|
166
|
+
"""Split the specified variable from the others."""
|
|
167
|
+
remaining_terms = {}
|
|
168
|
+
exponent = 0
|
|
169
|
+
for var, expo in self._vars:
|
|
170
|
+
if var == variable:
|
|
171
|
+
exponent = expo
|
|
172
|
+
else:
|
|
173
|
+
remaining_terms[var] = expo
|
|
174
|
+
return exponent, Monomial(self.get_coefficient(), remaining_terms)
|
|
175
|
+
|
|
176
|
+
def reduce_exponents(self, d):
|
|
177
|
+
|
|
178
|
+
assert isinstance(d, dict)
|
|
179
|
+
|
|
180
|
+
vars = [(var, expo - d[var]) for var, expo in self._vars]
|
|
181
|
+
vars = tuple([(var, expo) for var, expo in vars if expo > 0])
|
|
182
|
+
|
|
183
|
+
return Monomial(self.get_coefficient(), vars)
|
|
184
|
+
|
|
185
|
+
@sage_method
|
|
186
|
+
def sage(self):
|
|
187
|
+
return (
|
|
188
|
+
self.get_coefficient() *
|
|
189
|
+
prod(sage_var(var) ** expo for var, expo in self.get_vars()))
|
|
190
|
+
|
|
191
|
+
# Definition of Polynomial class
|
|
192
|
+
|
|
193
|
+
class Polynomial():
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
>>> m1 = Monomial(1, (('t', 1), ('x', 1), ('y', 1)))
|
|
197
|
+
>>> m2 = Monomial(3, (('t', 2),))
|
|
198
|
+
>>> m3 = Monomial(1, (('t', 6),))
|
|
199
|
+
>>> p1 = Polynomial( (m1, m2, m3) )
|
|
200
|
+
>>> p2 = Polynomial.parse_string('3 * t * t + t ^ 6 + x * t * y')
|
|
201
|
+
>>> p3 = Polynomial.parse_string('t * x * y + t^6 + 3 * t^2')
|
|
202
|
+
>>> p1 == p2
|
|
203
|
+
True
|
|
204
|
+
>>> p2 == p3
|
|
205
|
+
True
|
|
206
|
+
>>> str(p1)
|
|
207
|
+
't * x * y + 3 * t^2 + t^6'
|
|
208
|
+
>>> p4 = Polynomial.parse_string('x + t^2')
|
|
209
|
+
>>> str(p4)
|
|
210
|
+
't^2 + x'
|
|
211
|
+
>>> p1 == p4
|
|
212
|
+
False
|
|
213
|
+
>>> str(p1 + p4)
|
|
214
|
+
't * x * y + 4 * t^2 + t^6 + x'
|
|
215
|
+
>>> str(p1 - p2)
|
|
216
|
+
''
|
|
217
|
+
>>> str(p1 * p4)
|
|
218
|
+
't * x^2 * y + 3 * t^2 * x + t^3 * x * y + 3 * t^4 + t^6 * x + t^8'
|
|
219
|
+
>>> str(p4 ** 5)
|
|
220
|
+
'5 * t^2 * x^4 + 10 * t^4 * x^3 + 10 * t^6 * x^2 + 5 * t^8 * x + t^10 + x^5'
|
|
221
|
+
>>> p5 = Polynomial.parse_string('x + 1')
|
|
222
|
+
>>> p6 = p5 ** 3
|
|
223
|
+
>>> str(p6)
|
|
224
|
+
'1 + 3 * x + 3 * x^2 + x^3'
|
|
225
|
+
>>> p7 = p6.substitute({'x':Polynomial.constant_polynomial(Fraction(5,3))})
|
|
226
|
+
>>> str(p7)
|
|
227
|
+
'512/27'
|
|
228
|
+
>>> p8 = Polynomial.parse_string('')
|
|
229
|
+
>>> p8 == Polynomial(())
|
|
230
|
+
True
|
|
231
|
+
>>> p6.is_constant()
|
|
232
|
+
False
|
|
233
|
+
>>> p7.is_constant()
|
|
234
|
+
True
|
|
235
|
+
>>> p7.get_constant()
|
|
236
|
+
Fraction(512, 27)
|
|
237
|
+
>>> p9 = p4.substitute({'t':p5})
|
|
238
|
+
>>> str(p9)
|
|
239
|
+
'1 + 3 * x + x^2'
|
|
240
|
+
>>> p1.variables()
|
|
241
|
+
['t', 'x', 'y']
|
|
242
|
+
>>> p1.is_univariate()
|
|
243
|
+
False
|
|
244
|
+
>>> p9.is_univariate()
|
|
245
|
+
True
|
|
246
|
+
>>> p1.leading_coefficient()
|
|
247
|
+
Traceback (most recent call last):
|
|
248
|
+
...
|
|
249
|
+
AssertionError
|
|
250
|
+
>>> p9.leading_coefficient()
|
|
251
|
+
1
|
|
252
|
+
>>> p6 = Polynomial.parse_string('1+x^2')
|
|
253
|
+
|
|
254
|
+
# >>> str(p4 % p6)
|
|
255
|
+
# '- 2 + 2 * x'
|
|
256
|
+
|
|
257
|
+
#>>> str(Polynomial.parse_string('4+3*x').make_monic())
|
|
258
|
+
#'(4/3) + x'
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
@classmethod
|
|
262
|
+
def constant_polynomial(cls, constant):
|
|
263
|
+
"""Construct a constant polynomial."""
|
|
264
|
+
return Polynomial((Monomial.constant_monomial(constant),))
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
def from_variable_name(cls, var):
|
|
268
|
+
"""Construct a polynomial consisting of a single variable."""
|
|
269
|
+
return Polynomial((Monomial.from_variable_name(var),))
|
|
270
|
+
|
|
271
|
+
# constructor takes a tuple of polynomials which are combined
|
|
272
|
+
|
|
273
|
+
def __init__(self, monomials=()):
|
|
274
|
+
|
|
275
|
+
# combine monomials with the same variables and exponents
|
|
276
|
+
# and bring them into canonical order
|
|
277
|
+
|
|
278
|
+
assert isinstance(monomials, tuple)
|
|
279
|
+
|
|
280
|
+
# create for each monomial a dictionary
|
|
281
|
+
# with key being the variables and exponents
|
|
282
|
+
# and value being the coefficient
|
|
283
|
+
|
|
284
|
+
list_of_vars_coeff_dicts = [
|
|
285
|
+
{monomial.get_vars(): monomial.get_coefficient()}
|
|
286
|
+
for monomial in monomials]
|
|
287
|
+
|
|
288
|
+
# combine the dictionaries using sum
|
|
289
|
+
combined_vars_coeff_dict = _combine_dicts(
|
|
290
|
+
list_of_vars_coeff_dicts,
|
|
291
|
+
_operator_type_policy)
|
|
292
|
+
|
|
293
|
+
# turn dictionary into a list of pairs (vars, coefficient)
|
|
294
|
+
# in canonical order
|
|
295
|
+
ordered_tuple_of_vars_coeff_pairs = (
|
|
296
|
+
_dict_to_ordered_tuple_of_pairs(combined_vars_coeff_dict))
|
|
297
|
+
|
|
298
|
+
# turn pairs into monomials, skip trivial monomials
|
|
299
|
+
combined_monomials = [
|
|
300
|
+
Monomial(coefficient, vars)
|
|
301
|
+
for vars, coefficient in ordered_tuple_of_vars_coeff_pairs
|
|
302
|
+
if _coefficient_is_non_trivial(coefficient)]
|
|
303
|
+
|
|
304
|
+
# convert to tuple
|
|
305
|
+
self._monomials = tuple(combined_monomials)
|
|
306
|
+
|
|
307
|
+
def __eq__(self, other):
|
|
308
|
+
return self._monomials == other._monomials
|
|
309
|
+
|
|
310
|
+
def __add__(self, other):
|
|
311
|
+
assert isinstance(other, Polynomial)
|
|
312
|
+
return Polynomial(self._monomials + other._monomials)
|
|
313
|
+
|
|
314
|
+
def __neg__(self):
|
|
315
|
+
return Polynomial(
|
|
316
|
+
tuple([-monomial for monomial in self._monomials]))
|
|
317
|
+
|
|
318
|
+
def __sub__(self, other):
|
|
319
|
+
return self + (-other)
|
|
320
|
+
|
|
321
|
+
def __pow__(self, other):
|
|
322
|
+
|
|
323
|
+
if isinstance(other, Polynomial):
|
|
324
|
+
assert other.is_constant()
|
|
325
|
+
other = other.get_constant()
|
|
326
|
+
|
|
327
|
+
assert isinstance(other, int)
|
|
328
|
+
assert other >= 0
|
|
329
|
+
if other == 0:
|
|
330
|
+
return Polynomial((Monomial.constant_monomial(1),))
|
|
331
|
+
if other == 1:
|
|
332
|
+
return self
|
|
333
|
+
if other % 2:
|
|
334
|
+
return self * (self ** (other - 1))
|
|
335
|
+
return (self * self) ** (other // 2)
|
|
336
|
+
|
|
337
|
+
def __mul__(self, other):
|
|
338
|
+
return Polynomial(tuple(
|
|
339
|
+
m * n for m in self._monomials for n in other._monomials))
|
|
340
|
+
|
|
341
|
+
def __mod__(self, other):
|
|
342
|
+
|
|
343
|
+
assert isinstance(other, Polynomial)
|
|
344
|
+
assert self.is_univariate()
|
|
345
|
+
assert other.is_univariate()
|
|
346
|
+
self.coefficient_type(Fraction)
|
|
347
|
+
|
|
348
|
+
if self.degree() < other.degree():
|
|
349
|
+
return self
|
|
350
|
+
|
|
351
|
+
other = other.convert_coefficients(Fraction)
|
|
352
|
+
other = other * Polynomial.constant_polynomial(
|
|
353
|
+
Fraction(1, 1) / other.leading_coefficient())
|
|
354
|
+
|
|
355
|
+
variable = other.variables()[0]
|
|
356
|
+
assert ((not other.variables())
|
|
357
|
+
or other.variables()[0] == variable)
|
|
358
|
+
|
|
359
|
+
rest = self
|
|
360
|
+
while rest.degree() >= other.degree():
|
|
361
|
+
degree_diff = rest.degree() - other.degree()
|
|
362
|
+
leading_coeff = rest.leading_coefficient()
|
|
363
|
+
rest = rest - (
|
|
364
|
+
Polynomial.constant_polynomial(leading_coeff)
|
|
365
|
+
* Polynomial.from_variable_name(variable) ** degree_diff
|
|
366
|
+
* other)
|
|
367
|
+
|
|
368
|
+
return rest
|
|
369
|
+
|
|
370
|
+
def __str__(self):
|
|
371
|
+
return self.to_string(default_print_coefficient_method)
|
|
372
|
+
|
|
373
|
+
__repr__ = __str__
|
|
374
|
+
|
|
375
|
+
# print
|
|
376
|
+
# a method to print the coefficients can be supplied
|
|
377
|
+
|
|
378
|
+
def to_string(self, print_coefficient_method):
|
|
379
|
+
s = " ".join(monomial.to_string(print_coefficient_method,
|
|
380
|
+
force_print_sign=True)
|
|
381
|
+
for monomial in self._monomials)
|
|
382
|
+
if s and s[0] == '+':
|
|
383
|
+
return s[1:].lstrip()
|
|
384
|
+
return s
|
|
385
|
+
|
|
386
|
+
def convert_coefficients(self, conversion_function):
|
|
387
|
+
"""Convert all coefficients using conversion_function."""
|
|
388
|
+
|
|
389
|
+
return Polynomial(tuple(
|
|
390
|
+
monomial.convert_coefficient(conversion_function)
|
|
391
|
+
for monomial in self._monomials))
|
|
392
|
+
|
|
393
|
+
def substitute(self, d):
|
|
394
|
+
"""
|
|
395
|
+
Take a dictionary mapping variable name -> polynomial and
|
|
396
|
+
replace each variable by the corresponding polynomial.
|
|
397
|
+
"""
|
|
398
|
+
variables = self.variables()
|
|
399
|
+
|
|
400
|
+
skip_computation = True
|
|
401
|
+
|
|
402
|
+
for v in variables:
|
|
403
|
+
if v in d:
|
|
404
|
+
skip_computation = False
|
|
405
|
+
|
|
406
|
+
if skip_computation:
|
|
407
|
+
return self
|
|
408
|
+
|
|
409
|
+
def substitute_monomial(monomial):
|
|
410
|
+
vars = monomial.get_vars()
|
|
411
|
+
|
|
412
|
+
new_vars = tuple(
|
|
413
|
+
(var, expo)
|
|
414
|
+
for var, expo in vars
|
|
415
|
+
if var not in d)
|
|
416
|
+
|
|
417
|
+
poly = Polynomial((
|
|
418
|
+
Monomial(monomial.get_coefficient(), new_vars),))
|
|
419
|
+
|
|
420
|
+
for var, expo in vars:
|
|
421
|
+
if var in d:
|
|
422
|
+
poly = poly * (d[var] ** expo)
|
|
423
|
+
|
|
424
|
+
return poly
|
|
425
|
+
|
|
426
|
+
return sum((substitute_monomial(monomial)
|
|
427
|
+
for monomial in self._monomials), Polynomial(()))
|
|
428
|
+
|
|
429
|
+
def variables(self):
|
|
430
|
+
"""Return a list of all variables in the polynomial."""
|
|
431
|
+
return sorted(set(
|
|
432
|
+
v for monomial in self._monomials for v in monomial.variables()))
|
|
433
|
+
|
|
434
|
+
def is_constant(self):
|
|
435
|
+
"""Return True iff the polynomial is constant."""
|
|
436
|
+
return not self.variables()
|
|
437
|
+
|
|
438
|
+
def get_constant(self):
|
|
439
|
+
"""Returns the constant term of this polynomial."""
|
|
440
|
+
constants = [monomial.get_coefficient()
|
|
441
|
+
for monomial in self._monomials
|
|
442
|
+
if not monomial.get_vars()]
|
|
443
|
+
assert len(constants) <= 1
|
|
444
|
+
if constants:
|
|
445
|
+
return constants[0]
|
|
446
|
+
else:
|
|
447
|
+
return 0
|
|
448
|
+
|
|
449
|
+
def is_univariate(self):
|
|
450
|
+
"""Return True iff the polynomial has at most one variable."""
|
|
451
|
+
return len(self.variables()) <= 1
|
|
452
|
+
|
|
453
|
+
def is_linear(self):
|
|
454
|
+
"""Assert univariance; return True iff this polynomial is linear."""
|
|
455
|
+
return self.is_univariate() and self.degree() == 1
|
|
456
|
+
|
|
457
|
+
def leading_coefficient(self):
|
|
458
|
+
"""
|
|
459
|
+
Assert univariance; return the leading coefficient.
|
|
460
|
+
"""
|
|
461
|
+
assert self.is_univariate()
|
|
462
|
+
# use that monomials are sorted by degree
|
|
463
|
+
if self._monomials:
|
|
464
|
+
return self._monomials[-1].get_coefficient()
|
|
465
|
+
else:
|
|
466
|
+
return 0
|
|
467
|
+
|
|
468
|
+
def is_monic(self):
|
|
469
|
+
"""Assert univariance; return True iff this polynomial is monic."""
|
|
470
|
+
return self.leading_coefficient() == 1
|
|
471
|
+
|
|
472
|
+
def get_coefficients(self, conversion_function=lambda x: x):
|
|
473
|
+
"""Assert univariance; return the coefficients in degree order."""
|
|
474
|
+
assert self.is_univariate()
|
|
475
|
+
degree = self.degree()
|
|
476
|
+
list_of_coefficients = (degree + 1) * [conversion_function(0)]
|
|
477
|
+
for monomial in self._monomials:
|
|
478
|
+
list_of_coefficients[degree - monomial.degree()] = (
|
|
479
|
+
conversion_function(monomial.get_coefficient()))
|
|
480
|
+
return list_of_coefficients
|
|
481
|
+
|
|
482
|
+
def get_any_coefficient(self):
|
|
483
|
+
if len(self._monomials) == 0:
|
|
484
|
+
return None
|
|
485
|
+
else:
|
|
486
|
+
return self._monomials[0].get_coefficient()
|
|
487
|
+
|
|
488
|
+
def degree(self, var=None):
|
|
489
|
+
"""Return the total degree of this polynomial."""
|
|
490
|
+
return max(
|
|
491
|
+
[monomial.degree(var) for monomial in self._monomials] + [0])
|
|
492
|
+
|
|
493
|
+
@classmethod
|
|
494
|
+
def parse_string(cls, s, parse_coefficient_function=None):
|
|
495
|
+
"""
|
|
496
|
+
Construct a polynomial from a string using an optional function to parse the
|
|
497
|
+
coefficients.
|
|
498
|
+
"""
|
|
499
|
+
if parse_coefficient_function is None:
|
|
500
|
+
return _parse_polynomial_from_string(s, parse_int_or_fraction)
|
|
501
|
+
return _parse_polynomial_from_string(s, parse_coefficient_function)
|
|
502
|
+
|
|
503
|
+
def coefficient_type(self, the_type=int):
|
|
504
|
+
"""Returns the type of the coefficients."""
|
|
505
|
+
for monomial in self._monomials:
|
|
506
|
+
the_type = _storage_type_policy(the_type, monomial.coefficient_type())
|
|
507
|
+
return the_type
|
|
508
|
+
|
|
509
|
+
def curried_polynomial(self, variable):
|
|
510
|
+
"""
|
|
511
|
+
Return a polynomial in the variable whose coefficients are polynomials in
|
|
512
|
+
the other variables.
|
|
513
|
+
"""
|
|
514
|
+
poly = Polynomial()
|
|
515
|
+
for monomial in self._monomials:
|
|
516
|
+
exponent, remainder = monomial.split_variable(variable)
|
|
517
|
+
poly = poly + (
|
|
518
|
+
(Polynomial.from_variable_name(variable) ** exponent).convert_coefficients(Polynomial.constant_polynomial) *
|
|
519
|
+
Polynomial.constant_polynomial(Polynomial((remainder,))))
|
|
520
|
+
return poly
|
|
521
|
+
|
|
522
|
+
def get_monomials(self):
|
|
523
|
+
return self._monomials
|
|
524
|
+
|
|
525
|
+
def factor_out_variables(self):
|
|
526
|
+
|
|
527
|
+
if not self._monomials:
|
|
528
|
+
return self
|
|
529
|
+
|
|
530
|
+
def intersect(lists):
|
|
531
|
+
s = set(lists[0])
|
|
532
|
+
for l in lists:
|
|
533
|
+
s &= set(l)
|
|
534
|
+
return s
|
|
535
|
+
|
|
536
|
+
non_trivial_variables = intersect(
|
|
537
|
+
[monomial.variables() for monomial in self._monomials])
|
|
538
|
+
|
|
539
|
+
lowest_powers = {var: 1000000 for var in non_trivial_variables}
|
|
540
|
+
|
|
541
|
+
def safe_dict(d, var):
|
|
542
|
+
if var in d:
|
|
543
|
+
return d[var]
|
|
544
|
+
return 0
|
|
545
|
+
|
|
546
|
+
for monomial in self._monomials:
|
|
547
|
+
for var, expo in monomial.get_vars():
|
|
548
|
+
lowest_powers[var] = min(safe_dict(lowest_powers, var), expo)
|
|
549
|
+
|
|
550
|
+
return Polynomial(tuple([monomial.reduce_exponents(lowest_powers)
|
|
551
|
+
for monomial in self._monomials]))
|
|
552
|
+
|
|
553
|
+
@sage_method
|
|
554
|
+
def sage(self):
|
|
555
|
+
return sum(m.sage() for m in self.get_monomials())
|
|
556
|
+
|
|
557
|
+
###############################################################
|
|
558
|
+
# Default functions for parsing and printing the coefficients
|
|
559
|
+
|
|
560
|
+
# The user will rewrite these for other types and supply to
|
|
561
|
+
# the respective methods of Monomial and Polynomial.
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def parse_int_coefficient(s):
|
|
565
|
+
coeff, rest = re.match('([0-9]*)(.*)', s).groups()
|
|
566
|
+
if coeff:
|
|
567
|
+
coeff = int(coeff)
|
|
568
|
+
else:
|
|
569
|
+
coeff = None
|
|
570
|
+
return coeff, rest
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def parse_int_or_fraction(s):
|
|
574
|
+
m = re.match('([0-9]+/[0-9]+)(.*)', s)
|
|
575
|
+
if m:
|
|
576
|
+
frac, rest = m.groups()
|
|
577
|
+
return Fraction(frac), rest
|
|
578
|
+
|
|
579
|
+
return parse_int_coefficient(s)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def parenthesis_coefficient_method(i):
|
|
583
|
+
if isinstance(i, int) or isinstance(i, Fraction):
|
|
584
|
+
return default_print_coefficient_method(i)
|
|
585
|
+
|
|
586
|
+
else:
|
|
587
|
+
return '+', '(%s)' % repr(i)
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def default_print_coefficient_method(i):
|
|
591
|
+
try:
|
|
592
|
+
sign = '+' if i >= 0 else '-'
|
|
593
|
+
if abs(i) == 1:
|
|
594
|
+
print_str = None
|
|
595
|
+
else:
|
|
596
|
+
print_str = str(abs(i))
|
|
597
|
+
return sign, print_str
|
|
598
|
+
except (TypeError, ValueError):
|
|
599
|
+
return uncomparable_print_coefficient_method(i)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def uncomparable_print_coefficient_method(i):
|
|
603
|
+
print_str = str(i)
|
|
604
|
+
if '+' in print_str or '-' in print_str:
|
|
605
|
+
return '+', '(%s)' % print_str
|
|
606
|
+
else:
|
|
607
|
+
return '+', print_str
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
##############################################################################
|
|
611
|
+
# Private Definitions
|
|
612
|
+
|
|
613
|
+
# Methods defining what coefficient types can be mixed a polynomial
|
|
614
|
+
# Type Mixing Policy: only int can be mixed with another type
|
|
615
|
+
|
|
616
|
+
def _storage_type_policy(type_a, type_b):
|
|
617
|
+
assert isinstance(type_a, type)
|
|
618
|
+
assert isinstance(type_b, type)
|
|
619
|
+
|
|
620
|
+
if type_a in [int]:
|
|
621
|
+
return type_b
|
|
622
|
+
if type_b in [int]:
|
|
623
|
+
return type_a
|
|
624
|
+
|
|
625
|
+
if not type_a == type_b:
|
|
626
|
+
|
|
627
|
+
print(type_a, type_b)
|
|
628
|
+
raise Exception("Bad _storage_type_policy call")
|
|
629
|
+
|
|
630
|
+
return type_a
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
def _operator_type_policy(obj_a, obj_b, op=operator.add):
|
|
634
|
+
|
|
635
|
+
try:
|
|
636
|
+
|
|
637
|
+
if type(obj_a) == type(obj_b):
|
|
638
|
+
return op(obj_a, obj_b)
|
|
639
|
+
if type(obj_a) in [int]:
|
|
640
|
+
return op(type(obj_b)(obj_a), obj_b)
|
|
641
|
+
if type(obj_b) in [int]:
|
|
642
|
+
return op(type(obj_a)(obj_b), obj_a)
|
|
643
|
+
|
|
644
|
+
raise Exception
|
|
645
|
+
|
|
646
|
+
except (TypeError, ValueError):
|
|
647
|
+
|
|
648
|
+
print(obj_a, obj_b)
|
|
649
|
+
print(type(obj_a), type(obj_b))
|
|
650
|
+
|
|
651
|
+
raise Exception("In _operator_type_policy, cannot apply operator")
|
|
652
|
+
|
|
653
|
+
# Definitions of parsable operators and their precedence
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
_operators = {
|
|
657
|
+
'+': operator.add,
|
|
658
|
+
'-': operator.sub,
|
|
659
|
+
'*': operator.mul,
|
|
660
|
+
'^': operator.pow}
|
|
661
|
+
|
|
662
|
+
_operator_precedence = {
|
|
663
|
+
None: 0,
|
|
664
|
+
'+': 1,
|
|
665
|
+
'-': 1,
|
|
666
|
+
'*': 2,
|
|
667
|
+
'^': 3}
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
def _apply_operator(op, l, r):
|
|
671
|
+
return _operators[op](l, r)
|
|
672
|
+
|
|
673
|
+
# Helper functions for parsing
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def _coefficient_is_non_trivial(c):
|
|
677
|
+
|
|
678
|
+
if isinstance(c, Polynomial):
|
|
679
|
+
return c._monomials
|
|
680
|
+
|
|
681
|
+
return not c == 0
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def _parse_variable(s):
|
|
685
|
+
r = re.match(r'([_A-Za-z][_A-Za-z0-9]*)(.*)$', s)
|
|
686
|
+
if r:
|
|
687
|
+
return r.groups()
|
|
688
|
+
else:
|
|
689
|
+
return None, s
|
|
690
|
+
|
|
691
|
+
# Parsing function for Polynomial
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
def _parse_polynomial_from_string(s, parse_coefficient_function):
|
|
695
|
+
|
|
696
|
+
# Stack holding the operands encountered
|
|
697
|
+
operand_stack = []
|
|
698
|
+
# Stack holding the operators encountered
|
|
699
|
+
# The stack includes "("
|
|
700
|
+
operator_stack = []
|
|
701
|
+
|
|
702
|
+
# Has there been an operand since the opening parenthesis
|
|
703
|
+
# e.g. parse things like "(+ x)"
|
|
704
|
+
no_operand_since_opening_parenthesis = [True]
|
|
705
|
+
|
|
706
|
+
def debug_print(s):
|
|
707
|
+
print("=" * 75)
|
|
708
|
+
print("Remaining string : ", s)
|
|
709
|
+
print("Operator Stack : ", operator_stack)
|
|
710
|
+
print("Operand Stack : ", operand_stack)
|
|
711
|
+
|
|
712
|
+
# pop the top operator from the stack and apply it to the
|
|
713
|
+
# two top operands from the stack, repeat as long as there are preceding
|
|
714
|
+
# operators left on the stack.
|
|
715
|
+
def eval_preceding_operators_on_stack(operator=None):
|
|
716
|
+
while operator_stack:
|
|
717
|
+
top_operator = operator_stack[-1]
|
|
718
|
+
|
|
719
|
+
# stop if the top operator is "("
|
|
720
|
+
if top_operator == '(':
|
|
721
|
+
return
|
|
722
|
+
|
|
723
|
+
# or if the top operator is not preceding
|
|
724
|
+
if (_operator_precedence[top_operator] <
|
|
725
|
+
_operator_precedence[operator]):
|
|
726
|
+
return
|
|
727
|
+
|
|
728
|
+
top_operator = operator_stack.pop()
|
|
729
|
+
r = operand_stack.pop()
|
|
730
|
+
l = operand_stack.pop()
|
|
731
|
+
|
|
732
|
+
operand_stack.append(
|
|
733
|
+
_apply_operator(top_operator, l, r))
|
|
734
|
+
|
|
735
|
+
# this function is called iteratively and consumes
|
|
736
|
+
# the next operator or operand from the string
|
|
737
|
+
def process_next_token(s):
|
|
738
|
+
s = s.lstrip()
|
|
739
|
+
|
|
740
|
+
# parse constants or variables and push them onto the operand stack
|
|
741
|
+
constant, rest = parse_coefficient_function(s)
|
|
742
|
+
if constant is not None:
|
|
743
|
+
operand_stack.append(Polynomial.constant_polynomial(constant))
|
|
744
|
+
no_operand_since_opening_parenthesis[0] = False
|
|
745
|
+
return rest
|
|
746
|
+
|
|
747
|
+
variable, rest = _parse_variable(s)
|
|
748
|
+
if variable:
|
|
749
|
+
operand_stack.append(Polynomial.from_variable_name(variable))
|
|
750
|
+
no_operand_since_opening_parenthesis[0] = False
|
|
751
|
+
return rest
|
|
752
|
+
|
|
753
|
+
# parse an operator and push it onto the stack
|
|
754
|
+
# after evaluating all preceding operators
|
|
755
|
+
#
|
|
756
|
+
# detect strings such as "(+ 3)" and push a null string
|
|
757
|
+
# onto the operand stack as to emulate parsing "(0 + 3)"
|
|
758
|
+
|
|
759
|
+
next_char, rest = s[0], s[1:]
|
|
760
|
+
|
|
761
|
+
if next_char in _operators:
|
|
762
|
+
operator = next_char
|
|
763
|
+
eval_preceding_operators_on_stack(operator)
|
|
764
|
+
operator_stack.append(operator)
|
|
765
|
+
|
|
766
|
+
if operator in '+-':
|
|
767
|
+
if no_operand_since_opening_parenthesis[0]:
|
|
768
|
+
operand_stack.append(Polynomial())
|
|
769
|
+
no_operand_since_opening_parenthesis[0] = False
|
|
770
|
+
|
|
771
|
+
return rest
|
|
772
|
+
|
|
773
|
+
# handle parenthesis
|
|
774
|
+
# an opening parenthesis is just popped onto the stack
|
|
775
|
+
# a closing parenthesis evaluates all operators on the stack
|
|
776
|
+
# until the corresponding opening parenthesis is encountered
|
|
777
|
+
if next_char in '()':
|
|
778
|
+
parenthesis = next_char
|
|
779
|
+
if parenthesis == '(':
|
|
780
|
+
operator_stack.append('(')
|
|
781
|
+
no_operand_since_opening_parenthesis[0] = True
|
|
782
|
+
else:
|
|
783
|
+
eval_preceding_operators_on_stack()
|
|
784
|
+
top_operator = operator_stack.pop()
|
|
785
|
+
assert top_operator == '('
|
|
786
|
+
return rest
|
|
787
|
+
|
|
788
|
+
# This place should not be reached when a well-formed polynomial is supplied
|
|
789
|
+
raise Exception("While parsing polynomial %s" % s)
|
|
790
|
+
|
|
791
|
+
# iterate through the string to parse
|
|
792
|
+
s = s.strip()
|
|
793
|
+
while s:
|
|
794
|
+
# debug_print(s)
|
|
795
|
+
s = process_next_token(s)
|
|
796
|
+
|
|
797
|
+
# finish any remaining operators on the stack
|
|
798
|
+
# debug_print(s)
|
|
799
|
+
eval_preceding_operators_on_stack(None)
|
|
800
|
+
# debug_print(s)
|
|
801
|
+
|
|
802
|
+
# check that the operator stack is empty
|
|
803
|
+
# the operand stack should only contain the result or maybe
|
|
804
|
+
# an additional empty polynomial
|
|
805
|
+
|
|
806
|
+
assert not operator_stack
|
|
807
|
+
|
|
808
|
+
if not operand_stack:
|
|
809
|
+
return Polynomial(())
|
|
810
|
+
|
|
811
|
+
assert (len(operand_stack) == 1
|
|
812
|
+
or (
|
|
813
|
+
len(operand_stack) == 2 and
|
|
814
|
+
operand_stack[0] == Polynomial()))
|
|
815
|
+
|
|
816
|
+
return operand_stack[-1]
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
# ## Other help functions to deal with the internal representation
|
|
820
|
+
|
|
821
|
+
# take a dictionary and turn it into a tuple of pairs sorted by keys
|
|
822
|
+
|
|
823
|
+
def _dict_to_ordered_tuple_of_pairs(d):
|
|
824
|
+
"""
|
|
825
|
+
>>> _dict_to_ordered_tuple_of_pairs(
|
|
826
|
+
... { 'key3':'value3', 'key1':'value1', 'key2':'value2' })
|
|
827
|
+
(('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3'))
|
|
828
|
+
"""
|
|
829
|
+
l = list(d.items())
|
|
830
|
+
l.sort(key=lambda x: x[0])
|
|
831
|
+
return tuple(l)
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
# given a list of dictionaries, combine values of the different
|
|
835
|
+
# dictionaries having the same key using combine_function.
|
|
836
|
+
|
|
837
|
+
def _combine_dicts(list_of_dicts, combine_function):
|
|
838
|
+
"""
|
|
839
|
+
>>> d = _combine_dicts(
|
|
840
|
+
... [ {'key1': 1, 'key2': 2},
|
|
841
|
+
... {'key1': 1} ],
|
|
842
|
+
... combine_function = operator.add)
|
|
843
|
+
>>> d['key1']
|
|
844
|
+
2
|
|
845
|
+
>>> d['key2']
|
|
846
|
+
2
|
|
847
|
+
"""
|
|
848
|
+
|
|
849
|
+
result = {}
|
|
850
|
+
for a_dict in list_of_dicts:
|
|
851
|
+
for k, v in list(a_dict.items()):
|
|
852
|
+
if k in result:
|
|
853
|
+
result[k] = combine_function(result[k], v)
|
|
854
|
+
else:
|
|
855
|
+
result[k] = v
|
|
856
|
+
return result
|