passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_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.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,1701 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
# sage.doctest: needs sage.symbolic
|
|
3
|
+
r"""
|
|
4
|
+
Tropical Varieties
|
|
5
|
+
|
|
6
|
+
A tropical variety is a piecewise-linear geometric object derived from
|
|
7
|
+
a classical algebraic variety by using tropical mathematics, where the
|
|
8
|
+
tropical semiring replaces the usual arithmetic operations.
|
|
9
|
+
|
|
10
|
+
AUTHORS:
|
|
11
|
+
|
|
12
|
+
- Verrel Rievaldo Wijaya (2024-06): initial version
|
|
13
|
+
|
|
14
|
+
REFERENCES:
|
|
15
|
+
|
|
16
|
+
- [Bru2014]_
|
|
17
|
+
- [Mac2015]_
|
|
18
|
+
- [Fil2017]_
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# ****************************************************************************
|
|
22
|
+
# Copyright (C) 2024 Verrel Rievaldo Wijaya <verrelrievaldo@gmail.com>
|
|
23
|
+
#
|
|
24
|
+
# This program is free software: you can redistribute it and/or modify
|
|
25
|
+
# it under the terms of the GNU General Public License as published by
|
|
26
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
27
|
+
# (at your option) any later version.
|
|
28
|
+
# https://www.gnu.org/licenses/
|
|
29
|
+
# ****************************************************************************
|
|
30
|
+
|
|
31
|
+
from sage.rings.infinity import infinity
|
|
32
|
+
from sage.rings.rational_field import QQ
|
|
33
|
+
from sage.structure.sage_object import SageObject
|
|
34
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TropicalVariety(UniqueRepresentation, SageObject):
|
|
38
|
+
r"""
|
|
39
|
+
A tropical variety in `\RR^n`.
|
|
40
|
+
|
|
41
|
+
A tropical variety is defined as a corner locus of tropical polynomial
|
|
42
|
+
function. This means it consist of all points in `\RR^n` for which
|
|
43
|
+
the minimum (maximum) of the function is attained at least twice.
|
|
44
|
+
|
|
45
|
+
We represent the tropical variety as a list of lists, where the
|
|
46
|
+
inner list consist of three parts. The first one is a parametric
|
|
47
|
+
equations for tropical roots. The second one is the condition
|
|
48
|
+
for parameters. The third one is the order of the corresponding
|
|
49
|
+
component.
|
|
50
|
+
|
|
51
|
+
INPUT:
|
|
52
|
+
|
|
53
|
+
- ``poly`` -- a :class:`TropicalMPolynomial`
|
|
54
|
+
|
|
55
|
+
ALGORITHM:
|
|
56
|
+
|
|
57
|
+
We need to determine a corner locus of this tropical polynomial
|
|
58
|
+
function, which is all points `(x_1, x_2, \ldots, x_n)` for which
|
|
59
|
+
the maximum (minimum) is obtained at least twice. First, we convert
|
|
60
|
+
each monomial to its corresponding linear function. Then for each two
|
|
61
|
+
monomials of polynomial, we find the points where their values are
|
|
62
|
+
equal. Since we attempt to solve the equality of two equations in `n`
|
|
63
|
+
variables, the solution set will be described by `n-1` parameters.
|
|
64
|
+
|
|
65
|
+
Next, we need to check if the value of previous two monomials at the
|
|
66
|
+
points in solution set is really the maximum (minimum) of function.
|
|
67
|
+
We do this by solving the inequality of the previous monomial with all
|
|
68
|
+
other monomials in the polynomial after substituting the parameter.
|
|
69
|
+
This will give us the condition of parameters. Each of this condition
|
|
70
|
+
is then combined by union operator. If this final condition is not an
|
|
71
|
+
empty set, then it represent one component of tropical root. Then we
|
|
72
|
+
calculate the weight of this particular component by the maximum of
|
|
73
|
+
gcd of the numbers `|i-k|` and `|j-l|` for all pairs `(i,j)` and
|
|
74
|
+
`(k,l)` such that the value of on this component is given by the
|
|
75
|
+
corresponding monomials.
|
|
76
|
+
|
|
77
|
+
EXAMPLES:
|
|
78
|
+
|
|
79
|
+
We construct a tropical variety in `\RR^2`, where it is called a
|
|
80
|
+
tropical curve::
|
|
81
|
+
|
|
82
|
+
sage: T = TropicalSemiring(QQ, use_min=False)
|
|
83
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
84
|
+
sage: p1 = R(1)*x + x*y + R(0); p1
|
|
85
|
+
0*x*y + 1*x + 0
|
|
86
|
+
sage: tv = p1.tropical_variety(); tv
|
|
87
|
+
Tropical curve of 0*x*y + 1*x + 0
|
|
88
|
+
sage: tv.components()
|
|
89
|
+
[[(t1, 1), [t1 >= -1], 1], [(-1, t1), [t1 <= 1], 1], [(-t1, t1), [t1 >= 1], 1]]
|
|
90
|
+
sage: tv.vertices()
|
|
91
|
+
{(-1, 1)}
|
|
92
|
+
sage: tv.plot() # needs sage.plot
|
|
93
|
+
Graphics object consisting of 3 graphics primitives
|
|
94
|
+
|
|
95
|
+
.. PLOT::
|
|
96
|
+
:width: 300 px
|
|
97
|
+
|
|
98
|
+
T = TropicalSemiring(QQ, use_min=False)
|
|
99
|
+
R = PolynomialRing(T, ('x,y'))
|
|
100
|
+
x, y = R.gen(), R.gen(1)
|
|
101
|
+
p1 = R(1)*x + x*y + R(0)
|
|
102
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
103
|
+
|
|
104
|
+
A slightly different result will be obtained if we use min-plus algebra
|
|
105
|
+
for the base tropical semiring::
|
|
106
|
+
|
|
107
|
+
sage: T = TropicalSemiring(QQ, use_min=True)
|
|
108
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
109
|
+
sage: p1 = R(1)*x + x*y + R(0)
|
|
110
|
+
sage: tv = p1.tropical_variety(); tv
|
|
111
|
+
Tropical curve of 0*x*y + 1*x + 0
|
|
112
|
+
sage: tv.components()
|
|
113
|
+
[[(t1, 1), [t1 <= -1], 1], [(-1, t1), [t1 >= 1], 1], [(-t1, t1), [t1 <= 1], 1]]
|
|
114
|
+
sage: tv.plot() # needs sage.plot
|
|
115
|
+
Graphics object consisting of 3 graphics primitives
|
|
116
|
+
|
|
117
|
+
.. PLOT::
|
|
118
|
+
:width: 300 px
|
|
119
|
+
|
|
120
|
+
T = TropicalSemiring(QQ, use_min=True)
|
|
121
|
+
R = PolynomialRing(T, ('x,y'))
|
|
122
|
+
x, y = R.gen(), R.gen(1)
|
|
123
|
+
p1 = R(1)*x + x*y + R(0)
|
|
124
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
125
|
+
|
|
126
|
+
Tropical variety can consist of multiple components with varying orders::
|
|
127
|
+
|
|
128
|
+
sage: T = TropicalSemiring(QQ, use_min=False)
|
|
129
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
130
|
+
sage: p1 = R(7) + T(4)*x + y + R(4)*x*y + R(3)*y^2 + R(-3)*x^2
|
|
131
|
+
sage: tv = p1.tropical_variety(); tv
|
|
132
|
+
Tropical curve of (-3)*x^2 + 4*x*y + 3*y^2 + 4*x + 0*y + 7
|
|
133
|
+
sage: tv.components()
|
|
134
|
+
[[(3, t1), [t1 <= 0], 1],
|
|
135
|
+
[(-t1 + 3, t1), [0 <= t1, t1 <= 2], 1],
|
|
136
|
+
[(t1, 2), [t1 <= 1], 2],
|
|
137
|
+
[(t1, 0), [3 <= t1, t1 <= 7], 1],
|
|
138
|
+
[(7, t1), [t1 <= 0], 1],
|
|
139
|
+
[(t1 - 1, t1), [2 <= t1], 1],
|
|
140
|
+
[(t1 + 7, t1), [0 <= t1], 1]]
|
|
141
|
+
sage: tv.plot() # needs sage.plot
|
|
142
|
+
Graphics object consisting of 8 graphics primitives
|
|
143
|
+
|
|
144
|
+
.. PLOT::
|
|
145
|
+
:width: 300 px
|
|
146
|
+
|
|
147
|
+
T = TropicalSemiring(QQ, use_min=False)
|
|
148
|
+
R = PolynomialRing(T, ('x,y'))
|
|
149
|
+
x, y = R.gen(), R.gen(1)
|
|
150
|
+
p1 = R(7) + T(4)*x + y + R(4)*x*y + R(3)*y**2 + R(-3)*x**2
|
|
151
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
152
|
+
|
|
153
|
+
If the tropical polynomial have `n>2` variables, then the result will be
|
|
154
|
+
a tropical hypersurface embedded in a real space `\RR^n`::
|
|
155
|
+
|
|
156
|
+
sage: T = TropicalSemiring(QQ)
|
|
157
|
+
sage: R.<w,x,y,z> = PolynomialRing(T)
|
|
158
|
+
sage: p1 = x*y + R(-1/2)*x*z + R(4)*z^2 + w*x
|
|
159
|
+
sage: tv = p1.tropical_variety(); tv
|
|
160
|
+
Tropical hypersurface of 0*w*x + 0*x*y + (-1/2)*x*z + 4*z^2
|
|
161
|
+
sage: tv.components()
|
|
162
|
+
[[(t1, t2, t3 - 1/2, t3), [t2 - 9/2 <= t3, t3 <= t1 + 1/2, t2 - 5 <= t1], 1],
|
|
163
|
+
[(t1, 2*t2 - t3 + 4, t3, t2), [t3 + 1/2 <= t2, t3 <= t1], 1],
|
|
164
|
+
[(t1, t2, t1, t3), [max(t1 + 1/2, 1/2*t1 + 1/2*t2 - 2) <= t3], 1],
|
|
165
|
+
[(t1, t2 + 9/2, t3, t2), [t2 <= min(t3 + 1/2, t1 + 1/2)], 1],
|
|
166
|
+
[(t1 - 1/2, t2, t3, t1), [t2 - 9/2 <= t1, t1 <= t3 + 1/2, t2 - 5 <= t3], 1],
|
|
167
|
+
[(2*t1 - t2 + 4, t2, t3, t1), [t1 <= min(1/2*t2 + 1/2*t3 - 2, t2 - 9/2)], 1]]
|
|
168
|
+
"""
|
|
169
|
+
def __init__(self, poly):
|
|
170
|
+
r"""
|
|
171
|
+
Initialize ``self``.
|
|
172
|
+
|
|
173
|
+
EXAMPLES::
|
|
174
|
+
|
|
175
|
+
sage: T = TropicalSemiring(QQ)
|
|
176
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
177
|
+
sage: tv = (x+y).tropical_variety()
|
|
178
|
+
sage: TestSuite(tv).run()
|
|
179
|
+
|
|
180
|
+
TESTS::
|
|
181
|
+
|
|
182
|
+
sage: from sage.rings.semirings.tropical_variety import TropicalVariety
|
|
183
|
+
sage: R.<x,y> = QQ[]
|
|
184
|
+
sage: p1 = x + y
|
|
185
|
+
sage: TropicalVariety(p1)
|
|
186
|
+
Traceback (most recent call last):
|
|
187
|
+
...
|
|
188
|
+
ValueError: x + y is not a multivariate tropical polynomial
|
|
189
|
+
"""
|
|
190
|
+
import operator
|
|
191
|
+
from itertools import combinations
|
|
192
|
+
|
|
193
|
+
from sage.arith.misc import gcd
|
|
194
|
+
from sage.rings.semirings.tropical_mpolynomial import TropicalMPolynomial
|
|
195
|
+
from sage.symbolic.relation import solve
|
|
196
|
+
from sage.symbolic.ring import SR
|
|
197
|
+
|
|
198
|
+
if not isinstance(poly, TropicalMPolynomial):
|
|
199
|
+
raise ValueError(f"{poly} is not a multivariate tropical polynomial")
|
|
200
|
+
|
|
201
|
+
self._poly = poly
|
|
202
|
+
self._hypersurface = []
|
|
203
|
+
tropical_roots = []
|
|
204
|
+
variables = [SR.var(name)
|
|
205
|
+
for name in poly.parent().variable_names()]
|
|
206
|
+
|
|
207
|
+
# Convert each term to its linear function
|
|
208
|
+
linear_eq = {}
|
|
209
|
+
pd = poly.monomial_coefficients()
|
|
210
|
+
for key in pd:
|
|
211
|
+
eq = sum(variables[i] * e for i, e in enumerate(key))
|
|
212
|
+
eq += pd[key].lift()
|
|
213
|
+
linear_eq[key] = eq
|
|
214
|
+
temp_keys = []
|
|
215
|
+
temp_order = []
|
|
216
|
+
|
|
217
|
+
# Checking for all possible combinations of two terms
|
|
218
|
+
for keys in combinations(pd, 2):
|
|
219
|
+
sol = solve(linear_eq[keys[0]] == linear_eq[keys[1]], variables)
|
|
220
|
+
|
|
221
|
+
# Parametric solution of the chosen two terms
|
|
222
|
+
final_sol = [s.right() for s in sol[0]]
|
|
223
|
+
xy_interval = []
|
|
224
|
+
xy_interval.append(tuple(final_sol))
|
|
225
|
+
|
|
226
|
+
# Comparing with other terms
|
|
227
|
+
min_max = linear_eq[keys[0]]
|
|
228
|
+
for i, v in enumerate(variables):
|
|
229
|
+
min_max = min_max.subs(**{str(v): final_sol[i]})
|
|
230
|
+
all_sol_compare = []
|
|
231
|
+
no_solution = False
|
|
232
|
+
for compare in pd:
|
|
233
|
+
if compare not in keys:
|
|
234
|
+
temp_compare = linear_eq[compare]
|
|
235
|
+
for i, v in enumerate(variables):
|
|
236
|
+
temp_compare = temp_compare.subs(**{str(v): final_sol[i]})
|
|
237
|
+
if min_max == temp_compare:
|
|
238
|
+
sol_compare = [[]]
|
|
239
|
+
elif poly.parent().base()._use_min:
|
|
240
|
+
sol_compare = solve(min_max < temp_compare, variables)
|
|
241
|
+
else:
|
|
242
|
+
sol_compare = solve(min_max > temp_compare, variables)
|
|
243
|
+
if sol_compare:
|
|
244
|
+
if isinstance(sol_compare[0], list):
|
|
245
|
+
if sol_compare[0]:
|
|
246
|
+
all_sol_compare.append(sol_compare[0][0])
|
|
247
|
+
else: # solution is unbounded on one side
|
|
248
|
+
all_sol_compare.append(sol_compare[0])
|
|
249
|
+
else:
|
|
250
|
+
no_solution = True
|
|
251
|
+
break
|
|
252
|
+
|
|
253
|
+
# Solve the condition for parameter
|
|
254
|
+
if not no_solution:
|
|
255
|
+
parameter = set()
|
|
256
|
+
for sol in all_sol_compare:
|
|
257
|
+
parameter = parameter.union(set(sol.variables()))
|
|
258
|
+
parameter_solution = solve(all_sol_compare, list(parameter))
|
|
259
|
+
if parameter_solution:
|
|
260
|
+
xy_interval.append(parameter_solution[0])
|
|
261
|
+
tropical_roots.append(xy_interval)
|
|
262
|
+
# Calculate the order
|
|
263
|
+
index_diff = [abs(ai - bi)
|
|
264
|
+
for ai, bi in zip(keys[0], keys[1])]
|
|
265
|
+
order = gcd(index_diff)
|
|
266
|
+
temp_order.append(order)
|
|
267
|
+
temp_keys.append(keys)
|
|
268
|
+
|
|
269
|
+
# Changing all the operator's symbol to <= or >=
|
|
270
|
+
self._keys = []
|
|
271
|
+
components = []
|
|
272
|
+
dim_param = 0
|
|
273
|
+
if tropical_roots:
|
|
274
|
+
dim_param = len(tropical_roots[0][0]) - 1
|
|
275
|
+
vars = [SR.var(f't{i}') for i in range(1, dim_param + 1)]
|
|
276
|
+
for arg in tropical_roots:
|
|
277
|
+
subs_dict = {}
|
|
278
|
+
index_vars = 0
|
|
279
|
+
new_eq = []
|
|
280
|
+
for eq in arg[0]:
|
|
281
|
+
var_eq = eq.variables()
|
|
282
|
+
for var in var_eq:
|
|
283
|
+
if var not in subs_dict:
|
|
284
|
+
subs_dict[var] = vars[index_vars]
|
|
285
|
+
index_vars += 1
|
|
286
|
+
new_eq.append(eq.subs(subs_dict))
|
|
287
|
+
new_eq = tuple(new_eq)
|
|
288
|
+
arg.remove(arg[0])
|
|
289
|
+
arg.insert(0, new_eq)
|
|
290
|
+
if not arg[1] or not isinstance(arg[1], list):
|
|
291
|
+
arg[1] = []
|
|
292
|
+
for var in vars:
|
|
293
|
+
expr1 = -infinity < var
|
|
294
|
+
expr2 = var < infinity
|
|
295
|
+
arg[1].append(expr1)
|
|
296
|
+
arg[1].append(expr2)
|
|
297
|
+
else:
|
|
298
|
+
params = arg[1]
|
|
299
|
+
arg.remove(params)
|
|
300
|
+
new_param = []
|
|
301
|
+
for param in params:
|
|
302
|
+
lhs = param.lhs().subs(subs_dict)
|
|
303
|
+
rhs = param.rhs().subs(subs_dict)
|
|
304
|
+
if param.operator() == operator.gt:
|
|
305
|
+
expr = lhs >= rhs
|
|
306
|
+
else:
|
|
307
|
+
expr = lhs <= rhs
|
|
308
|
+
new_param.append(expr)
|
|
309
|
+
arg.insert(1, new_param)
|
|
310
|
+
components.append(arg)
|
|
311
|
+
|
|
312
|
+
# Determine the order of each component
|
|
313
|
+
self._vars = vars
|
|
314
|
+
final_order = []
|
|
315
|
+
for i, component in enumerate(components):
|
|
316
|
+
if component not in self._hypersurface:
|
|
317
|
+
self._hypersurface.append(component)
|
|
318
|
+
final_order.append(temp_order[i])
|
|
319
|
+
self._keys.append(temp_keys[i])
|
|
320
|
+
else:
|
|
321
|
+
index = self._hypersurface.index(component)
|
|
322
|
+
if temp_order[i] > final_order[index]:
|
|
323
|
+
final_order[index] = temp_order[i]
|
|
324
|
+
self._keys[index] = temp_keys[i]
|
|
325
|
+
for i in range(len(self._hypersurface)):
|
|
326
|
+
self._hypersurface[i].append(final_order[i])
|
|
327
|
+
|
|
328
|
+
def dimension(self):
|
|
329
|
+
"""
|
|
330
|
+
Return the dimension of ``self``.
|
|
331
|
+
|
|
332
|
+
EXAMPLES::
|
|
333
|
+
|
|
334
|
+
sage: T = TropicalSemiring(QQ)
|
|
335
|
+
sage: R.<a,x,y,z> = PolynomialRing(T)
|
|
336
|
+
sage: p1 = x*y + R(-1)*x*z
|
|
337
|
+
sage: p1.tropical_variety().dimension()
|
|
338
|
+
4
|
|
339
|
+
"""
|
|
340
|
+
return self._poly.parent().ngens()
|
|
341
|
+
|
|
342
|
+
def number_of_components(self):
|
|
343
|
+
"""
|
|
344
|
+
Return the number of components that make up ``self``.
|
|
345
|
+
|
|
346
|
+
EXAMPLES::
|
|
347
|
+
|
|
348
|
+
sage: T = TropicalSemiring(QQ)
|
|
349
|
+
sage: R.<a,x,y,z> = PolynomialRing(T)
|
|
350
|
+
sage: p1 = x*y*a + x*z + y^2 + a*x + y + z
|
|
351
|
+
sage: p1.tropical_variety().number_of_components()
|
|
352
|
+
13
|
|
353
|
+
"""
|
|
354
|
+
from sage.rings.integer_ring import ZZ
|
|
355
|
+
return ZZ(len(self._hypersurface))
|
|
356
|
+
|
|
357
|
+
def _repr_(self):
|
|
358
|
+
"""
|
|
359
|
+
Return a string representation of ``self``.
|
|
360
|
+
|
|
361
|
+
EXAMPLES::
|
|
362
|
+
|
|
363
|
+
sage: T = TropicalSemiring(QQ)
|
|
364
|
+
sage: R.<w,x,y,z> = PolynomialRing(T)
|
|
365
|
+
sage: (w).tropical_variety()
|
|
366
|
+
Tropical hypersurface of 0*w
|
|
367
|
+
"""
|
|
368
|
+
return f"Tropical hypersurface of {self._poly}"
|
|
369
|
+
|
|
370
|
+
def _latex_(self):
|
|
371
|
+
r"""
|
|
372
|
+
Return a latex representation of ``self``.
|
|
373
|
+
|
|
374
|
+
EXAMPLES::
|
|
375
|
+
|
|
376
|
+
sage: T = TropicalSemiring(QQ)
|
|
377
|
+
sage: R.<w,x,y,z> = PolynomialRing(T)
|
|
378
|
+
sage: tv = (R(1)*w^2 + x*y*z + R(-1)).tropical_variety()
|
|
379
|
+
sage: latex(tv)
|
|
380
|
+
TV\left(0 x y z + 1 w^{2} + \left(-1\right)\right)
|
|
381
|
+
"""
|
|
382
|
+
return f"TV\\left({self._poly._latex_()}\\right)"
|
|
383
|
+
|
|
384
|
+
def components(self):
|
|
385
|
+
"""
|
|
386
|
+
Return all components of ``self``.
|
|
387
|
+
|
|
388
|
+
EXAMPLES::
|
|
389
|
+
|
|
390
|
+
sage: T = TropicalSemiring(QQ)
|
|
391
|
+
sage: R.<a,x,y,z> = PolynomialRing(T)
|
|
392
|
+
sage: tv = (a+x+y+z).tropical_variety()
|
|
393
|
+
sage: tv.components()
|
|
394
|
+
[[(t1, t1, t2, t3), [t1 <= min(t3, t2)], 1],
|
|
395
|
+
[(t1, t2, t1, t3), [t1 <= t3, t1 <= t2], 1],
|
|
396
|
+
[(t1, t2, t3, t1), [t1 <= min(t3, t2)], 1],
|
|
397
|
+
[(t1, t2, t2, t3), [t2 <= t3, t2 <= t1], 1],
|
|
398
|
+
[(t1, t2, t3, t2), [t2 <= min(t3, t1)], 1],
|
|
399
|
+
[(t1, t2, t3, t3), [t3 <= min(t1, t2)], 1]]
|
|
400
|
+
"""
|
|
401
|
+
return self._hypersurface
|
|
402
|
+
|
|
403
|
+
def _components_intersection(self):
|
|
404
|
+
r"""
|
|
405
|
+
Return the intersection of three or more components of ``self``.
|
|
406
|
+
|
|
407
|
+
For a tropical variety in `\RR^n`, the intersection is characterized
|
|
408
|
+
by a linear equation in `\RR^{n-1}`. Specifically, this becomes a
|
|
409
|
+
vertex for tropical curve and an edges for tropical surface.
|
|
410
|
+
|
|
411
|
+
OUTPUT:
|
|
412
|
+
|
|
413
|
+
A dictionary where the keys represent component indices and the
|
|
414
|
+
values are lists of tuples. Each tuple contains a parametric
|
|
415
|
+
equation of points and the corresponding parameter's condition.
|
|
416
|
+
|
|
417
|
+
EXAMPLES:
|
|
418
|
+
|
|
419
|
+
In two dimension, it will provide vertices that are incident with
|
|
420
|
+
each component::
|
|
421
|
+
|
|
422
|
+
sage: T = TropicalSemiring(QQ)
|
|
423
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
424
|
+
sage: p1 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
425
|
+
sage: tv = p1.tropical_variety()
|
|
426
|
+
sage: tv._components_intersection()
|
|
427
|
+
{0: [((-2, 0), {})],
|
|
428
|
+
1: [((-2, 0), {})],
|
|
429
|
+
2: [((-1, -3), {})],
|
|
430
|
+
3: [((-2, 0), {}), ((-1, 0), {})],
|
|
431
|
+
4: [((-1, -3), {}), ((-1, 0), {})],
|
|
432
|
+
5: [((-1, -3), {})],
|
|
433
|
+
6: [((-1, 0), {}), ((3, 4), {})],
|
|
434
|
+
7: [((3, 4), {})],
|
|
435
|
+
8: [((3, 4), {})]}
|
|
436
|
+
|
|
437
|
+
In three dimensions, it will provide all parametric equations of
|
|
438
|
+
lines that lie within each component::
|
|
439
|
+
|
|
440
|
+
sage: T = TropicalSemiring(QQ)
|
|
441
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
442
|
+
sage: p1 = x + y + z + x^2
|
|
443
|
+
sage: tv = p1.tropical_variety()
|
|
444
|
+
sage: tv._components_intersection()
|
|
445
|
+
{0: [((t2, t2, t2), {0 <= t2}), ((0, 0, t2), {0 <= t2})],
|
|
446
|
+
1: [((0, t2, 0), {0 <= t2}), ((t2, t2, t2), {0 <= t2})],
|
|
447
|
+
2: [((0, t1, 0), {0 <= t1}), ((0, 0, t2), {0 <= t2})],
|
|
448
|
+
3: [((t1, t1, t1), {0 <= t1}), ((t1, 2*t1, 2*t1), {t1 <= 0})],
|
|
449
|
+
4: [((1/2*t2, t2, t2), {t2 <= 0}), ((0, 0, t2), {0 <= t2})],
|
|
450
|
+
5: [((0, t2, 0), {0 <= t2}), ((1/2*t2, t2, t2), {t2 <= 0})]}
|
|
451
|
+
"""
|
|
452
|
+
import operator
|
|
453
|
+
|
|
454
|
+
from sage.functions.min_max import max_symbolic, min_symbolic
|
|
455
|
+
from sage.sets.set import Set
|
|
456
|
+
from sage.symbolic.relation import solve
|
|
457
|
+
|
|
458
|
+
def update_result(result):
|
|
459
|
+
sol_param = solve(new_expr, vars)
|
|
460
|
+
sol_param_sim = set()
|
|
461
|
+
for sol in sol_param:
|
|
462
|
+
if sol == []:
|
|
463
|
+
for v in vars:
|
|
464
|
+
if v != var:
|
|
465
|
+
sol_param_sim.add(v < infinity)
|
|
466
|
+
elif isinstance(sol, list):
|
|
467
|
+
for eqn in sol:
|
|
468
|
+
if eqn.operator() == operator.eq:
|
|
469
|
+
if not eqn.rhs().is_numeric():
|
|
470
|
+
eqn_var = eqn.rhs().variables()
|
|
471
|
+
param_var = [v for v in eqn_var if v in vars]
|
|
472
|
+
if not param_var:
|
|
473
|
+
v = eqn.lhs()
|
|
474
|
+
if v != var:
|
|
475
|
+
sol_param_sim.add(v < infinity)
|
|
476
|
+
elif eqn.operator() == operator.lt:
|
|
477
|
+
sol_param_sim.add(eqn.lhs() <= eqn.rhs())
|
|
478
|
+
elif eqn.operator() == operator.gt:
|
|
479
|
+
sol_param_sim.add(eqn.lhs() >= eqn.rhs())
|
|
480
|
+
else:
|
|
481
|
+
sol_param_sim.add(sol)
|
|
482
|
+
|
|
483
|
+
# Checking there are no conditions with the same variables
|
|
484
|
+
# that use the <= and >= operators simultaneously
|
|
485
|
+
unique_sol_param = set()
|
|
486
|
+
temp = list(sol_param_sim)
|
|
487
|
+
op_temp = {i: set(temp[i].operands()) for i in range(len(temp))}
|
|
488
|
+
for s_value in op_temp.values():
|
|
489
|
+
match_keys = [k for k, v in op_temp.items() if v == s_value]
|
|
490
|
+
if len(match_keys) == 1:
|
|
491
|
+
for i in match_keys:
|
|
492
|
+
unique_sol_param.add(temp[i])
|
|
493
|
+
|
|
494
|
+
if (unique_sol_param) or (self.dimension() == 2):
|
|
495
|
+
if not unique_sol_param:
|
|
496
|
+
unique_sol_param = Set()
|
|
497
|
+
if index not in result:
|
|
498
|
+
result[index] = [(tuple(points), unique_sol_param)]
|
|
499
|
+
else:
|
|
500
|
+
result[index].append((tuple(points), unique_sol_param))
|
|
501
|
+
|
|
502
|
+
result = {}
|
|
503
|
+
vars = self._vars
|
|
504
|
+
for index, comp in enumerate(self._hypersurface):
|
|
505
|
+
for expr in comp[1]:
|
|
506
|
+
left = expr.lhs()
|
|
507
|
+
right = expr.rhs()
|
|
508
|
+
# If the lhs contains a min or max operator
|
|
509
|
+
if (left.operator() == max_symbolic) or (left.operator() == min_symbolic):
|
|
510
|
+
for operand in expr.lhs().operands():
|
|
511
|
+
points = list(comp[0])
|
|
512
|
+
new_expr = [e.subs(**{str(right): operand}) for e in comp[1]]
|
|
513
|
+
for i, p in enumerate(points):
|
|
514
|
+
new_eq = p.subs(**{str(right): operand})
|
|
515
|
+
points[i] = new_eq
|
|
516
|
+
update_result(result)
|
|
517
|
+
# If the rhs contains a min or max operator
|
|
518
|
+
elif (right.operator() == max_symbolic) or (right.operator() == min_symbolic):
|
|
519
|
+
for operand in expr.rhs().operands():
|
|
520
|
+
points = list(comp[0])
|
|
521
|
+
new_expr = [e.subs(**{str(left): operand}) for e in comp[1]]
|
|
522
|
+
for i, p in enumerate(points):
|
|
523
|
+
new_eq = p.subs(**{str(left): operand})
|
|
524
|
+
points[i] = new_eq
|
|
525
|
+
update_result(result)
|
|
526
|
+
else:
|
|
527
|
+
var = expr.variables()[0]
|
|
528
|
+
points = list(comp[0])
|
|
529
|
+
subs_expr = solve(left == right, var)[0].rhs()
|
|
530
|
+
new_expr = [e.subs(**{str(var): subs_expr}) for e in comp[1]]
|
|
531
|
+
for i, p in enumerate(points):
|
|
532
|
+
new_eq = p.subs(**{str(var): subs_expr})
|
|
533
|
+
points[i] = new_eq
|
|
534
|
+
update_result(result)
|
|
535
|
+
return result
|
|
536
|
+
|
|
537
|
+
def weight_vectors(self):
|
|
538
|
+
r"""
|
|
539
|
+
Return the weight vectors for each unique intersection of
|
|
540
|
+
components of ``self``.
|
|
541
|
+
|
|
542
|
+
Weight vectors are a list of vectors associated with each
|
|
543
|
+
unique intersection of the components of tropical variety.
|
|
544
|
+
Each vector is a normal vector to a component with respect
|
|
545
|
+
to the unique intersection lying within that component.
|
|
546
|
+
|
|
547
|
+
Assume ``self`` is a `n`-dimensional tropical variety.
|
|
548
|
+
Suppose `L` is an intersection lying within the components
|
|
549
|
+
`S_1, \ldots, S_k` with respective weights `w_1, \ldots, w_k`.
|
|
550
|
+
This `L` is a linear structure in `\RR^{n-1}` and has `n-1`
|
|
551
|
+
direction vectors `d_1,d_2,\ldots, d_{n-1}`. Each component
|
|
552
|
+
`S_1, \ldots, S_k` has a normal vector `n_1, \ldots, n_k`.
|
|
553
|
+
Then, we scale each normal vector to an integer vector such
|
|
554
|
+
that the greatest common divisor of its elements is 1.
|
|
555
|
+
|
|
556
|
+
The weight vector of a component `S_i` with respect to `L`
|
|
557
|
+
can be found by calculating the cross product between direction
|
|
558
|
+
vectors of `L` and normal vector `n_i`.These vectors will
|
|
559
|
+
satisfy the balancing condition `\sum_{i=1}^k w_k v_k = 0`.
|
|
560
|
+
|
|
561
|
+
OUTPUT:
|
|
562
|
+
|
|
563
|
+
A tuple of three dictionaries. The first dictionary contains
|
|
564
|
+
equations representing the intersections. The second dictionary
|
|
565
|
+
contains indices of components that contains the intersection.
|
|
566
|
+
The third dictionary contains lists of vectors.
|
|
567
|
+
|
|
568
|
+
EXAMPLES:
|
|
569
|
+
|
|
570
|
+
Weight vectors of tropical surface::
|
|
571
|
+
|
|
572
|
+
sage: T = TropicalSemiring(QQ)
|
|
573
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
574
|
+
sage: p = x^2 + R(-1)*y + z + R(1)
|
|
575
|
+
sage: tv = p.tropical_variety()
|
|
576
|
+
sage: tv.weight_vectors()
|
|
577
|
+
({0: ((1/2*u2, u2 + 1, u2), {u2 <= 1}),
|
|
578
|
+
1: ((1/2, 2, u2), {1 <= u2}),
|
|
579
|
+
2: ((1/2, u2, 1), {2 <= u2}),
|
|
580
|
+
3: ((u1, 2, 1), {(1/2) <= u1})},
|
|
581
|
+
{0: [0, 1, 3], 1: [0, 2, 4], 2: [1, 2, 5], 3: [3, 4, 5]},
|
|
582
|
+
{0: [(1, 2, -5/2), (1, -5/2, 2), (-2, 1/2, 1/2)],
|
|
583
|
+
1: [(-1, -2, 0), (0, 2, 0), (1, 0, 0)],
|
|
584
|
+
2: [(1, 0, 2), (0, 0, -2), (-1, 0, 0)],
|
|
585
|
+
3: [(0, 1, 1), (0, 0, -1), (0, -1, 0)]})
|
|
586
|
+
|
|
587
|
+
TESTS:
|
|
588
|
+
|
|
589
|
+
Checking the balance condition of weight vectors::
|
|
590
|
+
|
|
591
|
+
sage: T = TropicalSemiring(QQ)
|
|
592
|
+
sage: R.<a,b,c,d> = PolynomialRing(T)
|
|
593
|
+
sage: f = R.random_element()
|
|
594
|
+
sage: vec = f.tropical_variety().weight_vectors()[2].values()
|
|
595
|
+
sage: all(a == vector([0,0,0,0]) for a in [sum(lst) for lst in vec]) # not tested (:issue:`39663`)
|
|
596
|
+
True
|
|
597
|
+
"""
|
|
598
|
+
from itertools import combinations
|
|
599
|
+
|
|
600
|
+
from sage.arith.misc import gcd
|
|
601
|
+
from sage.calculus.functional import diff
|
|
602
|
+
from sage.matrix.constructor import matrix
|
|
603
|
+
from sage.modules.free_module_element import vector, zero_vector
|
|
604
|
+
from sage.symbolic.relation import solve
|
|
605
|
+
from sage.symbolic.ring import SR
|
|
606
|
+
|
|
607
|
+
dim = self.dimension()
|
|
608
|
+
t = SR.var('t')
|
|
609
|
+
t_vars = [SR.var(f't{i}') for i in range(dim)]
|
|
610
|
+
u_vars = [SR.var(f'u{i}') for i in range(dim)]
|
|
611
|
+
convert_tu = dict(zip(t_vars, u_vars))
|
|
612
|
+
CI = self._components_intersection()
|
|
613
|
+
unique_line = set()
|
|
614
|
+
index_line = {}
|
|
615
|
+
line_comps = {}
|
|
616
|
+
index = 0
|
|
617
|
+
|
|
618
|
+
# Find the unique intersection between multiple components and
|
|
619
|
+
# the indices of the components containing this intersection.
|
|
620
|
+
for i, lines in CI.items():
|
|
621
|
+
for line in lines:
|
|
622
|
+
eqn = line[0]
|
|
623
|
+
is_unique = True
|
|
624
|
+
for uniq in unique_line:
|
|
625
|
+
subs_index = -1
|
|
626
|
+
for j in range(dim):
|
|
627
|
+
if eqn[j] != uniq[j]:
|
|
628
|
+
subs_index = j
|
|
629
|
+
break
|
|
630
|
+
if subs_index == -1:
|
|
631
|
+
new_line = eqn
|
|
632
|
+
is_unique = False
|
|
633
|
+
break
|
|
634
|
+
subs_dict = {}
|
|
635
|
+
while len(subs_dict) != dim-2 and subs_index < dim:
|
|
636
|
+
eq1 = eqn[subs_index].subs(subs_dict)
|
|
637
|
+
vib = None
|
|
638
|
+
for unk in eq1.variables():
|
|
639
|
+
if unk not in subs_dict:
|
|
640
|
+
if unk in t_vars:
|
|
641
|
+
vib = unk
|
|
642
|
+
break
|
|
643
|
+
if vib:
|
|
644
|
+
eq1 = eq1.subs(**{str(vib): t})
|
|
645
|
+
eq2 = uniq[subs_index]
|
|
646
|
+
temp_sol = solve(eq1 == eq2, t)
|
|
647
|
+
if temp_sol:
|
|
648
|
+
temp_sol = temp_sol[0].rhs()
|
|
649
|
+
if not temp_sol.is_numeric():
|
|
650
|
+
subs_dict[vib] = temp_sol
|
|
651
|
+
subs_index += 1
|
|
652
|
+
if subs_dict:
|
|
653
|
+
new_line = []
|
|
654
|
+
for l in eqn:
|
|
655
|
+
for key, value in subs_dict.items():
|
|
656
|
+
l = l.subs(key == value)
|
|
657
|
+
new_line.append(l)
|
|
658
|
+
if tuple(new_line) in unique_line:
|
|
659
|
+
is_unique = False
|
|
660
|
+
break
|
|
661
|
+
if is_unique:
|
|
662
|
+
new_eqn = tuple([eq.subs(convert_tu) for eq in eqn])
|
|
663
|
+
cdns = line[1]
|
|
664
|
+
new_cdn = {cdn.subs(convert_tu) for cdn in cdns}
|
|
665
|
+
unique_line.add(new_eqn)
|
|
666
|
+
index_line[index] = (new_eqn, new_cdn)
|
|
667
|
+
line_comps[index] = [i]
|
|
668
|
+
index += 1
|
|
669
|
+
else:
|
|
670
|
+
match_key = [k for k, v in index_line.items() if v[0] == tuple(new_line)][0]
|
|
671
|
+
line_comps[match_key].append(i)
|
|
672
|
+
|
|
673
|
+
WV = {i: [] for i in range(len(line_comps)) if len(line_comps[i]) > 1}
|
|
674
|
+
for k in WV:
|
|
675
|
+
# Calculate direction vector of the line
|
|
676
|
+
dir_vecs = []
|
|
677
|
+
line = index_line[k][0]
|
|
678
|
+
all_var = set()
|
|
679
|
+
for l in line:
|
|
680
|
+
for v in l.variables():
|
|
681
|
+
all_var.add(v)
|
|
682
|
+
for vpar in all_var:
|
|
683
|
+
par_drv = [QQ(diff(l, vpar)) for l in line]
|
|
684
|
+
par_drv = vector(par_drv)
|
|
685
|
+
dir_vecs.append(par_drv)
|
|
686
|
+
|
|
687
|
+
# Calculate the outgoing normal vector of each surface in the
|
|
688
|
+
# direction of the line
|
|
689
|
+
for i in line_comps[k]:
|
|
690
|
+
surface = self._hypersurface[i][0]
|
|
691
|
+
drv_vectors = []
|
|
692
|
+
for vpar in self._vars:
|
|
693
|
+
temp_vec = [QQ(diff(s, vpar)) for s in surface]
|
|
694
|
+
temp_vec = vector(temp_vec)
|
|
695
|
+
drv_vectors.append(temp_vec)
|
|
696
|
+
temp = [t_vars]
|
|
697
|
+
temp.extend(drv_vectors)
|
|
698
|
+
vec_matrix = matrix(SR, temp)
|
|
699
|
+
normal_vec = vec_matrix.det()
|
|
700
|
+
temp_nor = [QQ(diff(normal_vec, tvar)) for tvar in t_vars]
|
|
701
|
+
normal_vec = vector(temp_nor)
|
|
702
|
+
normal_vec *= 1/gcd(normal_vec)
|
|
703
|
+
|
|
704
|
+
# Calculate the weight vector
|
|
705
|
+
temp_final = [t_vars]
|
|
706
|
+
temp_final.extend(dir_vecs)
|
|
707
|
+
temp_final.append(normal_vec)
|
|
708
|
+
vec_matrix = matrix(SR, temp_final)
|
|
709
|
+
weight_vec = vec_matrix.det()
|
|
710
|
+
temp_weight = [QQ(diff(weight_vec, tvar)) for tvar in t_vars]
|
|
711
|
+
weight_vec = vector(temp_weight)
|
|
712
|
+
order = self._hypersurface[i][2]
|
|
713
|
+
weight_vec *= order
|
|
714
|
+
WV[k].append(weight_vec)
|
|
715
|
+
|
|
716
|
+
balance = False
|
|
717
|
+
for i in range(1, len(WV[k])+1):
|
|
718
|
+
for j in combinations(range(len(WV[k])), i):
|
|
719
|
+
test_vectors = list(WV[k])
|
|
720
|
+
for idx in j:
|
|
721
|
+
test_vectors[idx] = -test_vectors[idx]
|
|
722
|
+
if sum(test_vectors) == zero_vector(QQ, dim):
|
|
723
|
+
WV[k] = test_vectors
|
|
724
|
+
balance = True
|
|
725
|
+
break
|
|
726
|
+
if balance:
|
|
727
|
+
break
|
|
728
|
+
|
|
729
|
+
return index_line, line_comps, WV
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
class TropicalSurface(TropicalVariety):
|
|
733
|
+
r"""
|
|
734
|
+
A tropical surface in `\RR^3`.
|
|
735
|
+
|
|
736
|
+
The tropical surface consists of planar regions and facets, which we
|
|
737
|
+
can call cells. These cells are connected in such a way that they form
|
|
738
|
+
a piecewise linear structure embedded in three-dimensional space. These
|
|
739
|
+
cells meet along edges, where the balancing condition is satisfied.
|
|
740
|
+
This balancing condition ensures that the sum of the outgoing normal
|
|
741
|
+
vectors at each edge is zero, reflecting the equilibrium.
|
|
742
|
+
|
|
743
|
+
EXAMPLES::
|
|
744
|
+
|
|
745
|
+
sage: T = TropicalSemiring(QQ, use_min=False)
|
|
746
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
747
|
+
sage: p1 = x + y + z + R(0)
|
|
748
|
+
sage: tv = p1.tropical_variety(); tv
|
|
749
|
+
Tropical surface of 0*x + 0*y + 0*z + 0
|
|
750
|
+
sage: tv.components()
|
|
751
|
+
[[(t1, t1, t2), [t2 <= t1, 0 <= t1], 1],
|
|
752
|
+
[(t1, t2, t1), [max(0, t2) <= t1], 1],
|
|
753
|
+
[(0, t1, t2), [t2 <= 0, t1 <= 0], 1],
|
|
754
|
+
[(t1, t2, t2), [max(0, t1) <= t2], 1],
|
|
755
|
+
[(t1, 0, t2), [t2 <= 0, t1 <= 0], 1],
|
|
756
|
+
[(t1, t2, 0), [t1 <= 0, t2 <= 0], 1]]
|
|
757
|
+
"""
|
|
758
|
+
def _axes(self):
|
|
759
|
+
r"""
|
|
760
|
+
Set the default axes for ``self``.
|
|
761
|
+
|
|
762
|
+
This default axes is used for the 3d plot. The axes is centered
|
|
763
|
+
around where the intersection of the components occurred so it
|
|
764
|
+
gives a nice visual representation for the interactions between
|
|
765
|
+
different components of the surface. Additionally, it enhances
|
|
766
|
+
the visibility and interpretation of how the components align
|
|
767
|
+
and interact in three-dimensional space.
|
|
768
|
+
|
|
769
|
+
OUTPUT:
|
|
770
|
+
|
|
771
|
+
A list of three lists, where the first inner list represent value
|
|
772
|
+
of x-axis, the second inner list represent value of y-axis, and
|
|
773
|
+
the third inner list represent value of z-axis. If there are
|
|
774
|
+
either no components or only one component, the axis will be set
|
|
775
|
+
to `[[-1, 1], [-1, 1], [-1, 1]]`.
|
|
776
|
+
|
|
777
|
+
EXAMPLES::
|
|
778
|
+
|
|
779
|
+
sage: T = TropicalSemiring(QQ)
|
|
780
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
781
|
+
sage: p1 = x
|
|
782
|
+
sage: p1.tropical_variety()._axes()
|
|
783
|
+
[[-1, 1], [-1, 1], [-1, 1]]
|
|
784
|
+
sage: p2 = x + y + z + x^2 + R(1)
|
|
785
|
+
sage: p2.tropical_variety()._axes()
|
|
786
|
+
[[-1, 2], [-1, 2], [-1, 2]]
|
|
787
|
+
"""
|
|
788
|
+
from sage.arith.srange import srange
|
|
789
|
+
from sage.symbolic.relation import solve
|
|
790
|
+
|
|
791
|
+
if not self._hypersurface:
|
|
792
|
+
return [[-1, 1], [-1, 1], [-1, 1]]
|
|
793
|
+
elif len(self._hypersurface) == 1:
|
|
794
|
+
bound = 1
|
|
795
|
+
for eqn in self._hypersurface[0][0]:
|
|
796
|
+
for op in eqn.operands():
|
|
797
|
+
if op.is_numeric():
|
|
798
|
+
bound = max(op, bound)
|
|
799
|
+
return [[-bound, bound]] * 3
|
|
800
|
+
|
|
801
|
+
u_set = set()
|
|
802
|
+
v_set = set()
|
|
803
|
+
for comp in self._hypersurface:
|
|
804
|
+
list_expr = []
|
|
805
|
+
temp_u = set()
|
|
806
|
+
temp_v = set()
|
|
807
|
+
for expr in comp[1]:
|
|
808
|
+
if expr.lhs().is_numeric():
|
|
809
|
+
if bool(expr.rhs() == self._vars[0]):
|
|
810
|
+
temp_u.add(expr.lhs())
|
|
811
|
+
else:
|
|
812
|
+
temp_v.add(expr.lhs())
|
|
813
|
+
elif expr.rhs().is_numeric():
|
|
814
|
+
if bool(expr.lhs() == self._vars[0]):
|
|
815
|
+
temp_u.add(expr.rhs())
|
|
816
|
+
else:
|
|
817
|
+
temp_v.add(expr.rhs())
|
|
818
|
+
else:
|
|
819
|
+
list_expr.append(expr)
|
|
820
|
+
if not temp_u:
|
|
821
|
+
temp_u.add(0)
|
|
822
|
+
if not temp_v:
|
|
823
|
+
temp_v.add(0)
|
|
824
|
+
for expr in list_expr:
|
|
825
|
+
for u in temp_u:
|
|
826
|
+
sol = solve(expr.subs(**{str(self._vars[0]): u}), self._vars[1])
|
|
827
|
+
if not sol:
|
|
828
|
+
temp_v.add(0)
|
|
829
|
+
elif not sol[0]:
|
|
830
|
+
temp_v.add(0)
|
|
831
|
+
else:
|
|
832
|
+
temp_v.add(sol[0][0].rhs())
|
|
833
|
+
for v in temp_v:
|
|
834
|
+
sol = solve(expr.subs(**{str(self._vars[1]): v}), self._vars[0])
|
|
835
|
+
if not sol:
|
|
836
|
+
temp_u.add(0)
|
|
837
|
+
elif not sol[0]:
|
|
838
|
+
temp_u.add(0)
|
|
839
|
+
else:
|
|
840
|
+
temp_u.add(sol[0][0].rhs())
|
|
841
|
+
u_set = u_set.union(temp_u)
|
|
842
|
+
v_set = v_set.union(temp_v)
|
|
843
|
+
axes = [[min(u_set)-1, max(u_set)+1], [min(v_set)-1, max(v_set)+1]]
|
|
844
|
+
|
|
845
|
+
# Calculate the z-axis
|
|
846
|
+
step = 10
|
|
847
|
+
du = (axes[0][1]-axes[0][0]) / step
|
|
848
|
+
dv = (axes[1][1]-axes[1][0]) / step
|
|
849
|
+
u_range = srange(axes[0][0], axes[0][1]+du, du)
|
|
850
|
+
v_range = srange(axes[1][0], axes[1][1]+dv, dv)
|
|
851
|
+
zmin, zmax = None, None
|
|
852
|
+
for comp in self._hypersurface:
|
|
853
|
+
for u in u_range:
|
|
854
|
+
for v in v_range:
|
|
855
|
+
checkpoint = True
|
|
856
|
+
for exp in comp[1]:
|
|
857
|
+
final_exp = exp.subs(**{str(self._vars[0]): u, str(self._vars[1]): v})
|
|
858
|
+
if not final_exp:
|
|
859
|
+
checkpoint = False
|
|
860
|
+
break
|
|
861
|
+
if checkpoint:
|
|
862
|
+
z = comp[0][2].subs(**{str(self._vars[0]): u, str(self._vars[1]): v})
|
|
863
|
+
if (zmin is None) and (zmax is None):
|
|
864
|
+
zmin = z
|
|
865
|
+
zmax = z
|
|
866
|
+
else:
|
|
867
|
+
zmin = min(z, zmin)
|
|
868
|
+
zmax = max(z, zmax)
|
|
869
|
+
axes.append([zmin, zmax])
|
|
870
|
+
return axes
|
|
871
|
+
|
|
872
|
+
def _polygon_vertices(self):
|
|
873
|
+
r"""
|
|
874
|
+
Return the vertices of the polygon for each components of ``self``
|
|
875
|
+
to be used for plotting.
|
|
876
|
+
|
|
877
|
+
OUTPUT:
|
|
878
|
+
|
|
879
|
+
A dictionary where the keys represent component indices and the
|
|
880
|
+
values are a set of points in three dimensional space.
|
|
881
|
+
|
|
882
|
+
EXAMPLES:
|
|
883
|
+
|
|
884
|
+
A tropical surface with only one component::
|
|
885
|
+
|
|
886
|
+
sage: T = TropicalSemiring(QQ)
|
|
887
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
888
|
+
sage: p1 = x + z
|
|
889
|
+
sage: tv1 = p1.tropical_variety()
|
|
890
|
+
sage: tv1._polygon_vertices()
|
|
891
|
+
{0: {(-1, -1, -1), (-1, 1, -1), (1, -1, 1), (1, 1, 1)}}
|
|
892
|
+
|
|
893
|
+
A tropical surface with multiple components::
|
|
894
|
+
|
|
895
|
+
sage: p2 = x^2 + x + y + z + R(1)
|
|
896
|
+
sage: tv2 = p2.tropical_variety()
|
|
897
|
+
sage: tv2._polygon_vertices() # long time
|
|
898
|
+
{0: {(0, 0, 0), (0, 0, 2), (1, 1, 1), (2, 2, 2)},
|
|
899
|
+
1: {(0, 0, 0), (0, 2, 0), (1, 1, 1), (2, 2, 2)},
|
|
900
|
+
2: {(0, 0, 0), (0, 0, 2), (0, 2, 0), (0, 2, 2)},
|
|
901
|
+
3: {(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2)},
|
|
902
|
+
4: {(-1/2, -1, -1), (0, 0, 0), (1, 1, 1), (2, -1, -1), (2, 1, 1)},
|
|
903
|
+
5: {(-1/2, -1, -1), (-1/2, -1, 2), (0, 0, 0), (0, 0, 2)},
|
|
904
|
+
6: {(1, 1, 1), (1, 1, 2), (2, 1, 1), (2, 1, 2)},
|
|
905
|
+
7: {(-1/2, -1, -1), (-1/2, 2, -1), (0, 0, 0), (0, 2, 0)},
|
|
906
|
+
8: {(1, 1, 1), (1, 2, 1), (2, 1, 1), (2, 2, 1)}}
|
|
907
|
+
"""
|
|
908
|
+
from sage.sets.real_set import RealSet
|
|
909
|
+
from sage.symbolic.relation import solve
|
|
910
|
+
|
|
911
|
+
poly_verts = {i: set() for i in range(self.number_of_components())}
|
|
912
|
+
axes = self._axes()
|
|
913
|
+
comps = self.components()
|
|
914
|
+
vars = self._vars
|
|
915
|
+
comps_int = self._components_intersection()
|
|
916
|
+
|
|
917
|
+
# Find the inside vertices (intersection of components)
|
|
918
|
+
for index, lines in comps_int.items():
|
|
919
|
+
for line in lines:
|
|
920
|
+
v = list(line[1])[0].variables()[0]
|
|
921
|
+
for param in line[1]:
|
|
922
|
+
left = param.lhs()
|
|
923
|
+
right = param.rhs()
|
|
924
|
+
if left.is_numeric():
|
|
925
|
+
vertex = [QQ(e.subs(**{str(v): left})) for e in line[0]]
|
|
926
|
+
poly_verts[index].add(tuple(vertex))
|
|
927
|
+
elif right.is_numeric():
|
|
928
|
+
vertex = [QQ(e.subs(**{str(v): right})) for e in line[0]]
|
|
929
|
+
poly_verts[index].add(tuple(vertex))
|
|
930
|
+
|
|
931
|
+
def find_edge_vertices(i):
|
|
932
|
+
j = (i+1) % 2
|
|
933
|
+
if i == 0: # interval for t1
|
|
934
|
+
interval = interval1
|
|
935
|
+
else: # interval for t2
|
|
936
|
+
interval = interval2
|
|
937
|
+
for p in [interval.inf(), interval.sup()]:
|
|
938
|
+
new_param = [e.subs(**{str(vars[i]): p}) for e in comps[index][1]]
|
|
939
|
+
sol = solve(new_param, vars[j])
|
|
940
|
+
if sol:
|
|
941
|
+
interval_param = RealSet()
|
|
942
|
+
for s in sol:
|
|
943
|
+
if s != []:
|
|
944
|
+
# Handle cases where 's' is not a list (s = r1 < +Infinity),
|
|
945
|
+
# or if 's' is a list, ensure that its elements define a real
|
|
946
|
+
# interval (catch invalid cases like s = [t1 == r100]).
|
|
947
|
+
try:
|
|
948
|
+
interval_param += RealSet(s[0])
|
|
949
|
+
except (IndexError, ValueError):
|
|
950
|
+
interval_param += RealSet(-infinity, infinity)
|
|
951
|
+
else:
|
|
952
|
+
interval_param += RealSet(-infinity, infinity)
|
|
953
|
+
interval_param = interval_param.intersection(interval2)
|
|
954
|
+
if is_doublevar:
|
|
955
|
+
int1 = RealSet()
|
|
956
|
+
for s1 in sol1:
|
|
957
|
+
subs1 = solve(s1[0].subs(**{str(vars[i]): p}), vars[j])
|
|
958
|
+
try:
|
|
959
|
+
int1 += RealSet(subs1[0])
|
|
960
|
+
except TypeError:
|
|
961
|
+
int1 += RealSet(subs1[0][0])
|
|
962
|
+
int2 = RealSet()
|
|
963
|
+
for s2 in sol2:
|
|
964
|
+
subs2 = solve(s2[0].subs(**{str(vars[i]): p}), vars[j])
|
|
965
|
+
try:
|
|
966
|
+
int2 += RealSet(subs2[0])
|
|
967
|
+
except TypeError:
|
|
968
|
+
int2 += RealSet(subs2[0][0])
|
|
969
|
+
final_int = int1.intersection(int2)
|
|
970
|
+
interval_param = interval_param.intersection(final_int)
|
|
971
|
+
if interval_param:
|
|
972
|
+
vertex1 = [QQ(e.subs(**{str(vars[i]): p, str(vars[j]): interval_param.inf()})) for e in comps[index][0]]
|
|
973
|
+
vertex2 = [QQ(e.subs(**{str(vars[i]): p, str(vars[j]): interval_param.sup()})) for e in comps[index][0]]
|
|
974
|
+
poly_verts[index].add(tuple(vertex1))
|
|
975
|
+
poly_verts[index].add(tuple(vertex2))
|
|
976
|
+
|
|
977
|
+
# Find the interval of parameter for outer vertex
|
|
978
|
+
for index in range(len(comps)):
|
|
979
|
+
interval1 = RealSet(-infinity, infinity) # represent t1
|
|
980
|
+
interval2 = RealSet(-infinity, infinity) # represent t2
|
|
981
|
+
is_doublevar = False
|
|
982
|
+
for i, point in enumerate(comps[index][0]):
|
|
983
|
+
pv = point.variables()
|
|
984
|
+
if len(pv) == 1:
|
|
985
|
+
temp1 = RealSet(solve(point >= axes[i][0], pv[0])[0][0])
|
|
986
|
+
temp2 = RealSet(solve(point <= axes[i][1], pv[0])[0][0])
|
|
987
|
+
temp = temp1.intersection(temp2)
|
|
988
|
+
if pv[0] == vars[0]:
|
|
989
|
+
interval1 = interval1.intersection(temp)
|
|
990
|
+
else:
|
|
991
|
+
interval2 = interval2.intersection(temp)
|
|
992
|
+
elif len(pv) == 2:
|
|
993
|
+
sol1 = solve(point >= axes[i][0], pv)
|
|
994
|
+
sol2 = solve(point <= axes[i][1], pv)
|
|
995
|
+
is_doublevar = True
|
|
996
|
+
|
|
997
|
+
# Find the edge vertices (those that touch the axes)
|
|
998
|
+
find_edge_vertices(0) # t1 fixed
|
|
999
|
+
find_edge_vertices(1) # t2 fixed
|
|
1000
|
+
return poly_verts
|
|
1001
|
+
|
|
1002
|
+
def plot(self, color='random'):
|
|
1003
|
+
"""
|
|
1004
|
+
Return the plot of ``self`` by constructing a polyhedron from
|
|
1005
|
+
vertices in ``self.polygon_vertices()``.
|
|
1006
|
+
|
|
1007
|
+
INPUT:
|
|
1008
|
+
|
|
1009
|
+
- ``color`` -- string or tuple that represent a color (default:
|
|
1010
|
+
``random``); ``random`` means each polygon will be assigned
|
|
1011
|
+
a different color. If instead a specific ``color`` is provided,
|
|
1012
|
+
then all polygon will be given the same color.
|
|
1013
|
+
|
|
1014
|
+
OUTPUT: Graphics3d Object
|
|
1015
|
+
|
|
1016
|
+
EXAMPLES:
|
|
1017
|
+
|
|
1018
|
+
A tropical surface that consist of only one cell::
|
|
1019
|
+
|
|
1020
|
+
sage: T = TropicalSemiring(QQ)
|
|
1021
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
1022
|
+
sage: p1 = x + z
|
|
1023
|
+
sage: tv = p1.tropical_variety()
|
|
1024
|
+
sage: tv.plot() # needs sage.plot
|
|
1025
|
+
Graphics3d Object
|
|
1026
|
+
|
|
1027
|
+
.. PLOT::
|
|
1028
|
+
:width: 300 px
|
|
1029
|
+
|
|
1030
|
+
T = TropicalSemiring(QQ)
|
|
1031
|
+
R = PolynomialRing(T, ('x,y,z'))
|
|
1032
|
+
x, y, z = R.gen(), R.gen(1), R.gen(2)
|
|
1033
|
+
p1 = x + z
|
|
1034
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
1035
|
+
|
|
1036
|
+
A tropical surface with multiple cells that exhibit complex and
|
|
1037
|
+
intriguing geometric structures::
|
|
1038
|
+
|
|
1039
|
+
sage: p2 = x^2 + x + y + z + R(1)
|
|
1040
|
+
sage: tv = p2.tropical_variety()
|
|
1041
|
+
sage: tv.plot() # long time # needs sage.plot
|
|
1042
|
+
Graphics3d Object
|
|
1043
|
+
|
|
1044
|
+
.. PLOT::
|
|
1045
|
+
:width: 300 px
|
|
1046
|
+
|
|
1047
|
+
T = TropicalSemiring(QQ)
|
|
1048
|
+
R = PolynomialRing(T, ('x,y,z'))
|
|
1049
|
+
x, y, z = R.gen(), R.gen(1), R.gen(2)
|
|
1050
|
+
p2 = x**2 + x + y + z + R(1)
|
|
1051
|
+
sphinx_plot(p2.tropical_variety().plot())
|
|
1052
|
+
"""
|
|
1053
|
+
from random import random
|
|
1054
|
+
|
|
1055
|
+
from sage.geometry.polyhedron.constructor import Polyhedron
|
|
1056
|
+
from sage.plot.graphics import Graphics
|
|
1057
|
+
|
|
1058
|
+
if color == 'random':
|
|
1059
|
+
colors = []
|
|
1060
|
+
for _ in range(self.number_of_components()):
|
|
1061
|
+
color = (random(), random(), random())
|
|
1062
|
+
colors.append(color)
|
|
1063
|
+
elif isinstance(color, str):
|
|
1064
|
+
colors = [color] * self.number_of_components()
|
|
1065
|
+
else:
|
|
1066
|
+
colors = color
|
|
1067
|
+
|
|
1068
|
+
combined_plot = Graphics()
|
|
1069
|
+
for i, vertex in self._polygon_vertices().items():
|
|
1070
|
+
points = list(vertex)
|
|
1071
|
+
plot = Polyhedron(vertices=points).plot(color=colors[i])
|
|
1072
|
+
combined_plot += plot
|
|
1073
|
+
return combined_plot
|
|
1074
|
+
|
|
1075
|
+
def _repr_(self):
|
|
1076
|
+
"""
|
|
1077
|
+
Return a string representation of ``self``.
|
|
1078
|
+
|
|
1079
|
+
EXAMPLES::
|
|
1080
|
+
|
|
1081
|
+
sage: T = TropicalSemiring(QQ)
|
|
1082
|
+
sage: R.<x,y,z> = PolynomialRing(T)
|
|
1083
|
+
sage: (x^4+z^2).tropical_variety()
|
|
1084
|
+
Tropical surface of 0*x^4 + 0*z^2
|
|
1085
|
+
"""
|
|
1086
|
+
return f"Tropical surface of {self._poly}"
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
class TropicalCurve(TropicalVariety):
|
|
1090
|
+
r"""
|
|
1091
|
+
A tropical curve in `\RR^2`.
|
|
1092
|
+
|
|
1093
|
+
The tropical curve consists of line segments and half-lines, which we
|
|
1094
|
+
call edges. These edges are connected in such a way that they form a
|
|
1095
|
+
piecewise linear graph embedded in the plane. These edges meet at
|
|
1096
|
+
a vertices, where the balancing condition is satisfied. This balancing
|
|
1097
|
+
condition ensures that the sum of the outgoing slopes at each vertex
|
|
1098
|
+
is zero, reflecting the equilibrium.
|
|
1099
|
+
|
|
1100
|
+
EXAMPLES:
|
|
1101
|
+
|
|
1102
|
+
We define some tropical curves::
|
|
1103
|
+
|
|
1104
|
+
sage: T = TropicalSemiring(QQ, use_min=False)
|
|
1105
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1106
|
+
sage: p1 = x + y + R(0)
|
|
1107
|
+
sage: tv1 = p1.tropical_variety(); tv1
|
|
1108
|
+
Tropical curve of 0*x + 0*y + 0
|
|
1109
|
+
sage: tv1.components()
|
|
1110
|
+
[[(t1, t1), [t1 >= 0], 1], [(0, t1), [t1 <= 0], 1], [(t1, 0), [t1 <= 0], 1]]
|
|
1111
|
+
sage: tv1.plot() # needs sage.plot
|
|
1112
|
+
Graphics object consisting of 3 graphics primitives
|
|
1113
|
+
|
|
1114
|
+
.. PLOT::
|
|
1115
|
+
:width: 300 px
|
|
1116
|
+
|
|
1117
|
+
T = TropicalSemiring(QQ, use_min=False)
|
|
1118
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1119
|
+
x, y = R.gen(), R.gen(1)
|
|
1120
|
+
p1 = x + y + R(0)
|
|
1121
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
1122
|
+
|
|
1123
|
+
::
|
|
1124
|
+
|
|
1125
|
+
sage: p2 = R(-2)*x^2 + R(-1)*x + R(1/2)*y + R(1/6)
|
|
1126
|
+
sage: tv2 = p2.tropical_variety()
|
|
1127
|
+
sage: tv2.components()
|
|
1128
|
+
[[(1/2*t1 + 5/4, t1), [(-1/3) <= t1], 1],
|
|
1129
|
+
[(13/12, t1), [t1 <= (-1/3)], 2],
|
|
1130
|
+
[(t1, -1/3), [t1 <= (13/12)], 1]]
|
|
1131
|
+
sage: tv2.plot() # needs sage.plot
|
|
1132
|
+
Graphics object consisting of 4 graphics primitives
|
|
1133
|
+
|
|
1134
|
+
.. PLOT::
|
|
1135
|
+
:width: 300 px
|
|
1136
|
+
|
|
1137
|
+
T = TropicalSemiring(QQ, use_min=False)
|
|
1138
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1139
|
+
x, y = R.gen(), R.gen(1)
|
|
1140
|
+
p2 = R(-2)*x**2 + R(-1)*x + R(1/2)*y + R(1/6)
|
|
1141
|
+
sphinx_plot(p2.tropical_variety().plot())
|
|
1142
|
+
|
|
1143
|
+
When two tropical polynomials are multiplied, the tropical curve of
|
|
1144
|
+
the resulting polynomial is the union of the tropical curves of the
|
|
1145
|
+
original polynomials::
|
|
1146
|
+
|
|
1147
|
+
sage: p3 = p1 * p2; p3
|
|
1148
|
+
(-2)*x^3 + (-2)*x^2*y + (-1)*x^2 + 1/2*x*y + 1/2*y^2 + 1/6*x + 1/2*y + 1/6
|
|
1149
|
+
sage: tv3 = p3.tropical_variety()
|
|
1150
|
+
sage: tv3.plot() # needs sage.plot
|
|
1151
|
+
Graphics object consisting of 11 graphics primitives
|
|
1152
|
+
|
|
1153
|
+
.. PLOT::
|
|
1154
|
+
:width: 300 px
|
|
1155
|
+
|
|
1156
|
+
T = TropicalSemiring(QQ, use_min=False)
|
|
1157
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1158
|
+
x, y = R.gen(), R.gen(1)
|
|
1159
|
+
p1 = x + y + R(0)
|
|
1160
|
+
p2 = R(-2)*x**2 + R(-1)*x + R(1/2)*y + R(1/6)
|
|
1161
|
+
p3 = p1 * p2
|
|
1162
|
+
sphinx_plot(p3.tropical_variety().plot())
|
|
1163
|
+
"""
|
|
1164
|
+
def _axes(self):
|
|
1165
|
+
"""
|
|
1166
|
+
Set the default axes for ``self``.
|
|
1167
|
+
|
|
1168
|
+
This default axes is used for plot of tropical curve and also the
|
|
1169
|
+
3d plot of tropical polynomial function. The axes is chosen by first
|
|
1170
|
+
find all vertices of this tropical curve. Then we choose the minimum
|
|
1171
|
+
and maximum of all x-component in this vertices to be the x-axis.
|
|
1172
|
+
The same apply to the y-axis.
|
|
1173
|
+
|
|
1174
|
+
OUTPUT:
|
|
1175
|
+
|
|
1176
|
+
A list of two lists, where the first inner list represent value of
|
|
1177
|
+
x-axis and the second inner list represent value of y-axis.
|
|
1178
|
+
|
|
1179
|
+
EXAMPLES::
|
|
1180
|
+
|
|
1181
|
+
sage: T = TropicalSemiring(QQ)
|
|
1182
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1183
|
+
sage: p1 = x^2
|
|
1184
|
+
sage: p1.tropical_variety()._axes()
|
|
1185
|
+
[[-1, 1], [-1, 1]]
|
|
1186
|
+
sage: p2 = R(12)*x*y + R(-2)*y^2 + R(16)*y + R(25)
|
|
1187
|
+
sage: p2.tropical_variety()._axes()
|
|
1188
|
+
[[-3/2, 1/2], [25/2, 29/2]]
|
|
1189
|
+
"""
|
|
1190
|
+
if self.number_of_components() == 0:
|
|
1191
|
+
return [[-1, 1], [-1, 1]]
|
|
1192
|
+
if self.number_of_components() <= 2:
|
|
1193
|
+
bound = 1
|
|
1194
|
+
for comps in self._hypersurface:
|
|
1195
|
+
eqns = comps[0]
|
|
1196
|
+
temp_operands = []
|
|
1197
|
+
for eq in eqns:
|
|
1198
|
+
if not eq.operator():
|
|
1199
|
+
temp_operands.append(eq)
|
|
1200
|
+
else:
|
|
1201
|
+
temp_operands += eq.operands()
|
|
1202
|
+
for op in temp_operands:
|
|
1203
|
+
if op.is_numeric():
|
|
1204
|
+
bound = max(abs(op), bound)
|
|
1205
|
+
return [[-bound, bound]] * 2
|
|
1206
|
+
|
|
1207
|
+
verts = self.vertices()
|
|
1208
|
+
xmin = xmax = list(verts)[0][0]
|
|
1209
|
+
for vertex in verts:
|
|
1210
|
+
if vertex[0] < xmin:
|
|
1211
|
+
xmin = vertex[0]
|
|
1212
|
+
elif vertex[0] > xmax:
|
|
1213
|
+
xmax = vertex[0]
|
|
1214
|
+
ymin = ymax = list(verts)[0][1]
|
|
1215
|
+
for vertex in verts:
|
|
1216
|
+
if vertex[1] < ymin:
|
|
1217
|
+
ymin = vertex[1]
|
|
1218
|
+
elif vertex[1] > ymax:
|
|
1219
|
+
ymax = vertex[1]
|
|
1220
|
+
return [[xmin-1, xmax+1], [ymin-1, ymax+1]]
|
|
1221
|
+
|
|
1222
|
+
def vertices(self):
|
|
1223
|
+
r"""
|
|
1224
|
+
Return all vertices of ``self``, which is the point where three or
|
|
1225
|
+
more edges intersect.
|
|
1226
|
+
|
|
1227
|
+
OUTPUT: a set of `(x,y)` points
|
|
1228
|
+
|
|
1229
|
+
EXAMPLES::
|
|
1230
|
+
|
|
1231
|
+
sage: T = TropicalSemiring(QQ)
|
|
1232
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1233
|
+
sage: p1 = x + y
|
|
1234
|
+
sage: p1.tropical_variety().vertices()
|
|
1235
|
+
set()
|
|
1236
|
+
sage: p2 = R(-2)*x^2 + R(-1)*x + R(1/2)*y + R(1/6)
|
|
1237
|
+
sage: p2.tropical_variety().vertices()
|
|
1238
|
+
{(1, -1/2), (7/6, -1/3)}
|
|
1239
|
+
"""
|
|
1240
|
+
if len(self._hypersurface) < 3:
|
|
1241
|
+
return set()
|
|
1242
|
+
return set(self._vertices_components().keys())
|
|
1243
|
+
|
|
1244
|
+
def _vertices_components(self):
|
|
1245
|
+
"""
|
|
1246
|
+
Return the index of components adjacent to each vertex of ``self``.
|
|
1247
|
+
|
|
1248
|
+
OUTPUT:
|
|
1249
|
+
|
|
1250
|
+
A dictionary where the keys represent the vertices, and the
|
|
1251
|
+
values are lists of tuples. Each tuple consists of the index
|
|
1252
|
+
of an adjacent edge (component) `e_i` and a number indicating
|
|
1253
|
+
the directionality of `e_i` relative to the vertex. The number
|
|
1254
|
+
is either -1 or 1.
|
|
1255
|
+
|
|
1256
|
+
EXAMPLES::
|
|
1257
|
+
|
|
1258
|
+
sage: T = TropicalSemiring(QQ)
|
|
1259
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1260
|
+
sage: p1 = R(0) + x + y + x*y + x^2*y + x*y^2
|
|
1261
|
+
sage: p1.tropical_variety()._vertices_components()
|
|
1262
|
+
{(0, 0): [(0, 1), (1, 1), (2, 1), (3, -1), (4, -1)]}
|
|
1263
|
+
sage: p2 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1264
|
+
sage: p2.tropical_variety()._vertices_components()
|
|
1265
|
+
{(-2, 0): [(0, -1), (1, 1), (3, 1)],
|
|
1266
|
+
(-1, -3): [(2, -1), (4, 1), (5, 1)],
|
|
1267
|
+
(-1, 0): [(3, -1), (4, -1), (6, 1)],
|
|
1268
|
+
(3, 4): [(6, -1), (7, 1), (8, 1)]}
|
|
1269
|
+
"""
|
|
1270
|
+
comp_vert = {}
|
|
1271
|
+
if len(self._hypersurface) >= 3:
|
|
1272
|
+
for i, component in enumerate(self._hypersurface):
|
|
1273
|
+
parametric_function = component[0]
|
|
1274
|
+
v = component[1][0].variables()[0]
|
|
1275
|
+
interval = self._parameter_intervals()[i]
|
|
1276
|
+
lower = interval[0].lower()
|
|
1277
|
+
upper = interval[0].upper()
|
|
1278
|
+
if lower != -infinity:
|
|
1279
|
+
x = parametric_function[0].subs(**{str(v): lower})
|
|
1280
|
+
y = parametric_function[1].subs(**{str(v): lower})
|
|
1281
|
+
if (x, y) not in comp_vert:
|
|
1282
|
+
comp_vert[(x, y)] = [(i, 1)]
|
|
1283
|
+
else:
|
|
1284
|
+
comp_vert[(x, y)].append((i, 1))
|
|
1285
|
+
if upper != infinity:
|
|
1286
|
+
x = parametric_function[0].subs(**{str(v): upper})
|
|
1287
|
+
y = parametric_function[1].subs(**{str(v): upper})
|
|
1288
|
+
if (x, y) not in comp_vert:
|
|
1289
|
+
comp_vert[(x, y)] = [(i, -1)]
|
|
1290
|
+
else:
|
|
1291
|
+
comp_vert[(x, y)].append((i, -1))
|
|
1292
|
+
return comp_vert
|
|
1293
|
+
|
|
1294
|
+
def weight_vectors(self):
|
|
1295
|
+
r"""
|
|
1296
|
+
Return the weight vectors for all vertices of ``self``.
|
|
1297
|
+
|
|
1298
|
+
Weight vectors are a list of vectors associated with each vertex
|
|
1299
|
+
of the curve. Each vector corresponds to an edge emanating from
|
|
1300
|
+
that vertex and points in the direction of the edge.
|
|
1301
|
+
|
|
1302
|
+
Suppose `v` is a vertex adjacent to the edges `e_1, \ldots, e_k`
|
|
1303
|
+
with respective weights `w_1, \ldots, w_k`. Every edge `e_i` is
|
|
1304
|
+
contained in a line (component) defined by an equation. Therefore,
|
|
1305
|
+
there exists a unique integer vector `v_i = (\alpha, \beta)` in
|
|
1306
|
+
the direction of `e_i` such that `\gcd(\alpha, \beta)=1`. Then,
|
|
1307
|
+
each vertex `v` yield the vectors `w_1 v_1, \ldots, w_k v_k`.
|
|
1308
|
+
These vectors will satisfy the following balancing condition:
|
|
1309
|
+
`\sum_{i=1}^k w_i v_i = 0`.
|
|
1310
|
+
|
|
1311
|
+
OUTPUT:
|
|
1312
|
+
|
|
1313
|
+
A dictionary where the keys represent the vertices, and the values
|
|
1314
|
+
are lists of vectors.
|
|
1315
|
+
|
|
1316
|
+
EXAMPLES::
|
|
1317
|
+
|
|
1318
|
+
sage: T = TropicalSemiring(QQ)
|
|
1319
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1320
|
+
sage: p1 = R(-2)*x^2 + R(-1)*x + R(1/2)*y + R(1/6)
|
|
1321
|
+
sage: p1.tropical_variety().weight_vectors()
|
|
1322
|
+
{(1, -1/2): [(0, 1), (-1, -2), (1, 1)],
|
|
1323
|
+
(7/6, -1/3): [(-1, -1), (0, 1), (1, 0)]}
|
|
1324
|
+
|
|
1325
|
+
sage: p2 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1326
|
+
sage: p2.tropical_variety().weight_vectors()
|
|
1327
|
+
{(-2, 0): [(-1, -1), (0, 1), (1, 0)],
|
|
1328
|
+
(-1, -3): [(-1, -1), (0, 1), (1, 0)],
|
|
1329
|
+
(-1, 0): [(-1, 0), (0, -1), (1, 1)],
|
|
1330
|
+
(3, 4): [(-1, -1), (0, 1), (1, 0)]}
|
|
1331
|
+
"""
|
|
1332
|
+
from sage.arith.misc import gcd
|
|
1333
|
+
from sage.calculus.functional import diff
|
|
1334
|
+
from sage.modules.free_module_element import vector
|
|
1335
|
+
|
|
1336
|
+
if not self._vertices_components():
|
|
1337
|
+
return {}
|
|
1338
|
+
|
|
1339
|
+
# Calculate the base vector in the direction of each edge
|
|
1340
|
+
temp_vectors = []
|
|
1341
|
+
par = self._hypersurface[0][1][0].variables()[0]
|
|
1342
|
+
for comp in self._hypersurface:
|
|
1343
|
+
dx = diff(comp[0][0], par)
|
|
1344
|
+
dy = diff(comp[0][1], par)
|
|
1345
|
+
multiplier = gcd(QQ(dx), QQ(dy))
|
|
1346
|
+
temp_vectors.append(vector([dx/multiplier, dy/multiplier]))
|
|
1347
|
+
|
|
1348
|
+
# Calculate the weight vectors of each vertex
|
|
1349
|
+
cov = self._vertices_components()
|
|
1350
|
+
result = {}
|
|
1351
|
+
for vertex in cov:
|
|
1352
|
+
vectors = []
|
|
1353
|
+
for comp in cov[vertex]:
|
|
1354
|
+
weight = self._hypersurface[comp[0]][2]
|
|
1355
|
+
vectors.append(weight*comp[1]*temp_vectors[comp[0]])
|
|
1356
|
+
result[vertex] = vectors
|
|
1357
|
+
return result
|
|
1358
|
+
|
|
1359
|
+
def is_smooth(self):
|
|
1360
|
+
r"""
|
|
1361
|
+
Return ``True`` if ``self`` is smooth and ``False`` otherwise.
|
|
1362
|
+
|
|
1363
|
+
Suppose `C` is a tropical curve of degree `d`. A tropical curve
|
|
1364
|
+
`C` is smooth if the dual subdivision of `C` consists of `d^2`
|
|
1365
|
+
triangles each having unit area `1/2`. This is equivalent with
|
|
1366
|
+
`C` having `d^2` vertices. These vertices are necessarily
|
|
1367
|
+
trivalent (has three adjacent edges).
|
|
1368
|
+
|
|
1369
|
+
EXAMPLES::
|
|
1370
|
+
|
|
1371
|
+
sage: T = TropicalSemiring(QQ)
|
|
1372
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1373
|
+
sage: p1 = x^2 + x + R(1)
|
|
1374
|
+
sage: p1.tropical_variety().is_smooth()
|
|
1375
|
+
False
|
|
1376
|
+
sage: p2 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1377
|
+
sage: p2.tropical_variety().is_smooth()
|
|
1378
|
+
True
|
|
1379
|
+
"""
|
|
1380
|
+
return len(self.vertices()) == self._poly.degree() ** 2
|
|
1381
|
+
|
|
1382
|
+
def is_simple(self):
|
|
1383
|
+
r"""
|
|
1384
|
+
Return ``True`` if ``self`` is simple and ``False`` otherwise.
|
|
1385
|
+
|
|
1386
|
+
A tropical curve `C` is called simple if each vertex is either
|
|
1387
|
+
trivalent or is locally the intersection of two line segments.
|
|
1388
|
+
Equivalently, `C` is simple if the corresponding subdivision
|
|
1389
|
+
consists only of triangles and parallelograms.
|
|
1390
|
+
|
|
1391
|
+
EXAMPLES::
|
|
1392
|
+
|
|
1393
|
+
sage: T = TropicalSemiring(QQ)
|
|
1394
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1395
|
+
sage: p1 = R(0) + x + y + x*y + x^2*y + x*y^2
|
|
1396
|
+
sage: p1.tropical_variety().is_simple()
|
|
1397
|
+
False
|
|
1398
|
+
sage: p2 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1399
|
+
sage: p2.tropical_variety().is_simple()
|
|
1400
|
+
True
|
|
1401
|
+
"""
|
|
1402
|
+
vov = self.weight_vectors()
|
|
1403
|
+
for vertex in self.vertices():
|
|
1404
|
+
if len(vov[vertex]) > 4:
|
|
1405
|
+
return False
|
|
1406
|
+
if len(vov[vertex]) == 4:
|
|
1407
|
+
if any(-v not in vov[vertex] for v in vov[vertex]):
|
|
1408
|
+
return False
|
|
1409
|
+
return True
|
|
1410
|
+
|
|
1411
|
+
def genus(self):
|
|
1412
|
+
r"""
|
|
1413
|
+
Return the genus of ``self``.
|
|
1414
|
+
|
|
1415
|
+
Let `t(C)` be the number of trivalent vertices, and let `r(C)` be
|
|
1416
|
+
the number of unbounded edges of `C`. The genus of simple tropical
|
|
1417
|
+
curve `C` is defined by the formula:
|
|
1418
|
+
|
|
1419
|
+
.. MATH::
|
|
1420
|
+
|
|
1421
|
+
g(C) = \frac{1}{2}t(C) - \frac{1}{2}r(C) + 1.
|
|
1422
|
+
|
|
1423
|
+
EXAMPLES::
|
|
1424
|
+
|
|
1425
|
+
sage: T = TropicalSemiring(QQ)
|
|
1426
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1427
|
+
sage: p1 = x^2 + y^2 + x*y
|
|
1428
|
+
sage: p1.tropical_variety().genus()
|
|
1429
|
+
1
|
|
1430
|
+
sage: p2 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1431
|
+
sage: p2.tropical_variety().genus()
|
|
1432
|
+
0
|
|
1433
|
+
|
|
1434
|
+
TESTS::
|
|
1435
|
+
|
|
1436
|
+
sage: T = TropicalSemiring(QQ)
|
|
1437
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1438
|
+
sage: p1 = R(0) + y + x^2*y + x*y^2
|
|
1439
|
+
sage: p1.tropical_variety().genus()
|
|
1440
|
+
Traceback (most recent call last):
|
|
1441
|
+
...
|
|
1442
|
+
ValueError: Tropical curve of 0*x^2*y + 0*x*y^2 + 0*y + 0 is not simple
|
|
1443
|
+
"""
|
|
1444
|
+
if not self.is_simple():
|
|
1445
|
+
raise ValueError(f"{self} is not simple")
|
|
1446
|
+
trivalent = 0 # number of trivalent vertices
|
|
1447
|
+
for vectors in self.weight_vectors().values():
|
|
1448
|
+
if len(vectors) == 3:
|
|
1449
|
+
trivalent += 1
|
|
1450
|
+
unbounded = 0 # number of unbounded edges
|
|
1451
|
+
for component in self._hypersurface:
|
|
1452
|
+
if len(component[1]) == 1:
|
|
1453
|
+
unbounded += 1
|
|
1454
|
+
return trivalent//2 - unbounded//2 + 1
|
|
1455
|
+
|
|
1456
|
+
def contribution(self):
|
|
1457
|
+
r"""
|
|
1458
|
+
Return the contribution of ``self``.
|
|
1459
|
+
|
|
1460
|
+
The contribution of a simple curve `C` is defined as the product
|
|
1461
|
+
of the normalized areas of all triangles in the corresponding
|
|
1462
|
+
dual subdivision. We just multiply positive integers attached to
|
|
1463
|
+
the trivalent vertices. The contribution of a trivalent vertex
|
|
1464
|
+
equals `w_1w_2|\det(v_1,v_2)|`, with `w_i` are the weights of
|
|
1465
|
+
the adjacent edges and `v_i` are their weight vectors. That
|
|
1466
|
+
formula is independent of the choice made because of the
|
|
1467
|
+
balancing condition `w_1v_1+w_2v_2+w_3v_3=0`.
|
|
1468
|
+
|
|
1469
|
+
EXAMPLES::
|
|
1470
|
+
|
|
1471
|
+
sage: T = TropicalSemiring(QQ)
|
|
1472
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1473
|
+
sage: p1 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3)
|
|
1474
|
+
sage: p1.tropical_variety().contribution()
|
|
1475
|
+
1
|
|
1476
|
+
sage: p2 = R(-1/3)*x^2 + R(1)*x*y + R(1)*y^2 + R(-1/3)*x + R(1/3)
|
|
1477
|
+
sage: p2.tropical_variety().contribution()
|
|
1478
|
+
16
|
|
1479
|
+
|
|
1480
|
+
TESTS::
|
|
1481
|
+
|
|
1482
|
+
sage: T = TropicalSemiring(QQ)
|
|
1483
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1484
|
+
sage: p1 = R(0) + x + x^2*y + x*y^2
|
|
1485
|
+
sage: p1.tropical_variety().contribution()
|
|
1486
|
+
Traceback (most recent call last):
|
|
1487
|
+
...
|
|
1488
|
+
ValueError: Tropical curve of 0*x^2*y + 0*x*y^2 + 0*x + 0 is not simple
|
|
1489
|
+
"""
|
|
1490
|
+
if not self.is_simple():
|
|
1491
|
+
raise ValueError(f"{self} is not simple")
|
|
1492
|
+
result = 1
|
|
1493
|
+
voc = self._vertices_components()
|
|
1494
|
+
vov = self.weight_vectors()
|
|
1495
|
+
for vertex in vov:
|
|
1496
|
+
if len(vov[vertex]) == 3:
|
|
1497
|
+
u1 = vov[vertex][0]
|
|
1498
|
+
u2 = vov[vertex][1]
|
|
1499
|
+
index1 = voc[vertex][0][0]
|
|
1500
|
+
index2 = voc[vertex][1][0]
|
|
1501
|
+
w1 = self._hypersurface[index1][2]
|
|
1502
|
+
w2 = self._hypersurface[index2][2]
|
|
1503
|
+
det = u1[0]*u2[1] - u1[1]*u2[0]
|
|
1504
|
+
result *= w1 * w2 * abs(det)
|
|
1505
|
+
return result
|
|
1506
|
+
|
|
1507
|
+
def _parameter_intervals(self):
|
|
1508
|
+
r"""
|
|
1509
|
+
Return the intervals of each component's parameter of ``self``.
|
|
1510
|
+
|
|
1511
|
+
OUTPUT: a list of ``RealSet``
|
|
1512
|
+
|
|
1513
|
+
EXAMPLES::
|
|
1514
|
+
|
|
1515
|
+
sage: T = TropicalSemiring(QQ)
|
|
1516
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1517
|
+
sage: p1 = y + y^2
|
|
1518
|
+
sage: p1.tropical_variety()._parameter_intervals()
|
|
1519
|
+
[(-oo, +oo)]
|
|
1520
|
+
sage: p2 = x^2 + R(-1)*x*y + R(-1)*x + R(1/3)
|
|
1521
|
+
sage: p2.tropical_variety()._parameter_intervals()
|
|
1522
|
+
[(-oo, 0], [0, +oo), [-1, 4/3], (-oo, 0], [0, +oo)]
|
|
1523
|
+
"""
|
|
1524
|
+
from sage.sets.real_set import RealSet
|
|
1525
|
+
|
|
1526
|
+
intervals = []
|
|
1527
|
+
R = self._poly.parent().base().base_ring()
|
|
1528
|
+
for component in self._hypersurface:
|
|
1529
|
+
if len(component[1]) == 1:
|
|
1530
|
+
interval = RealSet(component[1][0])
|
|
1531
|
+
else:
|
|
1532
|
+
lower = component[1][0].left()
|
|
1533
|
+
upper = component[1][1].right()
|
|
1534
|
+
if lower == -infinity:
|
|
1535
|
+
interval = RealSet(-infinity, infinity)
|
|
1536
|
+
else:
|
|
1537
|
+
interval = RealSet([R(lower), R(upper)])
|
|
1538
|
+
intervals.append(interval)
|
|
1539
|
+
return intervals
|
|
1540
|
+
|
|
1541
|
+
def plot(self):
|
|
1542
|
+
"""
|
|
1543
|
+
Return the plot of ``self``.
|
|
1544
|
+
|
|
1545
|
+
Generates a visual representation of the tropical curve in cartesian
|
|
1546
|
+
coordinates. The plot shows piecewise-linear segments representing
|
|
1547
|
+
each components. The axes are centered around the vertices.
|
|
1548
|
+
|
|
1549
|
+
OUTPUT:
|
|
1550
|
+
|
|
1551
|
+
A Graphics object. The weight of the component will be written if it
|
|
1552
|
+
is greater or equal than 2. The weight is written near the vertex.
|
|
1553
|
+
|
|
1554
|
+
EXAMPLES:
|
|
1555
|
+
|
|
1556
|
+
A polynomial with only two terms will give one straight line::
|
|
1557
|
+
|
|
1558
|
+
sage: T = TropicalSemiring(QQ)
|
|
1559
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1560
|
+
sage: (y+R(1)).tropical_variety().components()
|
|
1561
|
+
[[(t1, 1), [-Infinity < t1, t1 < +Infinity], 1]]
|
|
1562
|
+
sage: (y+R(1)).tropical_variety().plot() # needs sage.plot
|
|
1563
|
+
Graphics object consisting of 1 graphics primitive
|
|
1564
|
+
|
|
1565
|
+
.. PLOT::
|
|
1566
|
+
:width: 300 px
|
|
1567
|
+
|
|
1568
|
+
T = TropicalSemiring(QQ)
|
|
1569
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1570
|
+
x, y = R.gen(), R.gen(1)
|
|
1571
|
+
sphinx_plot((y+R(1)).tropical_variety().plot())
|
|
1572
|
+
|
|
1573
|
+
An intriguing and fascinating tropical curve can be obtained with
|
|
1574
|
+
a more complex tropical polynomial::
|
|
1575
|
+
|
|
1576
|
+
sage: p1 = R(1) + R(2)*x + R(3)*y + R(6)*x*y + R(10)*x*y^2
|
|
1577
|
+
sage: p1.tropical_variety().components()
|
|
1578
|
+
[[(-1, t1), [-2 <= t1], 1],
|
|
1579
|
+
[(t1, -2), [-1 <= t1], 1],
|
|
1580
|
+
[(t1 + 1, t1), [-4 <= t1, t1 <= -2], 1],
|
|
1581
|
+
[(t1, -4), [t1 <= -3], 2],
|
|
1582
|
+
[(-t1 - 7, t1), [t1 <= -4], 1]]
|
|
1583
|
+
sage: p1.tropical_variety().plot() # needs sage.plot
|
|
1584
|
+
Graphics object consisting of 6 graphics primitives
|
|
1585
|
+
|
|
1586
|
+
.. PLOT::
|
|
1587
|
+
:width: 300 px
|
|
1588
|
+
|
|
1589
|
+
T = TropicalSemiring(QQ)
|
|
1590
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1591
|
+
x, y = R.gen(), R.gen(1)
|
|
1592
|
+
p1 = R(1) + R(2)*x + R(3)*y + R(6)*x*y + R(10)*x*y**2
|
|
1593
|
+
sphinx_plot(p1.tropical_variety().plot())
|
|
1594
|
+
|
|
1595
|
+
Another tropical polynomial with numerous components, resulting
|
|
1596
|
+
in a more intricate structure::
|
|
1597
|
+
|
|
1598
|
+
sage: p2 = (x^6 + R(4)*x^4*y^2 + R(2)*x^3*y^3 + R(3)*x^2*y^4
|
|
1599
|
+
....: + x*y^5 + R(7)*x^2 + R(5)*x*y + R(3)*y^2 + R(2)*x
|
|
1600
|
+
....: + y + R(10))
|
|
1601
|
+
sage: p2.tropical_variety().plot() # long time # needs sage.plot
|
|
1602
|
+
Graphics object consisting of 11 graphics primitives
|
|
1603
|
+
|
|
1604
|
+
.. PLOT::
|
|
1605
|
+
:width: 300 px
|
|
1606
|
+
|
|
1607
|
+
T = TropicalSemiring(QQ)
|
|
1608
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1609
|
+
x, y = R.gen(), R.gen(1)
|
|
1610
|
+
p2 = (x**6 + R(4)*x**4*y**2 + R(2)*x**3*y**3 + R(3)*x**2*y**4
|
|
1611
|
+
+ x*y**5 + R(7)*x**2 + R(5)*x*y + R(3)*y**2 + R(2)*x
|
|
1612
|
+
+ y + R(10))
|
|
1613
|
+
sphinx_plot(p2.tropical_variety().plot())
|
|
1614
|
+
|
|
1615
|
+
::
|
|
1616
|
+
|
|
1617
|
+
sage: p3 = (R(8) + R(4)*x + R(2)*y + R(1)*x^2 + x*y + R(1)*y^2
|
|
1618
|
+
....: + R(2)*x^3 + x^2*y + x*y^2 + R(4)*y^3 + R(8)*x^4
|
|
1619
|
+
....: + R(4)*x^3*y + x^2*y^2 + R(2)*x*y^3 + y^4)
|
|
1620
|
+
sage: p3.tropical_variety().plot() # long time
|
|
1621
|
+
Graphics object consisting of 23 graphics primitives
|
|
1622
|
+
|
|
1623
|
+
.. PLOT::
|
|
1624
|
+
:width: 300 px
|
|
1625
|
+
|
|
1626
|
+
T = TropicalSemiring(QQ)
|
|
1627
|
+
R = PolynomialRing(T, ('x,y'))
|
|
1628
|
+
x, y = R.gen(), R.gen(1)
|
|
1629
|
+
p3 = (R(8) + R(4)*x + R(2)*y + R(1)*x**2 + x*y + R(1)*y**2
|
|
1630
|
+
+ R(2)*x**3 + x**2*y + x*y**2 + R(4)*y**3 + R(8)*x**4
|
|
1631
|
+
+ R(4)*x**3*y + x**2*y**2 + R(2)*x*y**3 + y**4)
|
|
1632
|
+
sphinx_plot(p3.tropical_variety().plot())
|
|
1633
|
+
"""
|
|
1634
|
+
from sage.plot.graphics import Graphics
|
|
1635
|
+
from sage.plot.plot import parametric_plot, plot
|
|
1636
|
+
from sage.plot.text import text
|
|
1637
|
+
|
|
1638
|
+
if not self._hypersurface:
|
|
1639
|
+
return plot(lambda x: float('nan'), {-1, 1})
|
|
1640
|
+
|
|
1641
|
+
combined_plot = Graphics()
|
|
1642
|
+
large_int = 100
|
|
1643
|
+
intervals = self._parameter_intervals()
|
|
1644
|
+
for i, component in enumerate(self._hypersurface):
|
|
1645
|
+
var = component[1][0].variables()[0]
|
|
1646
|
+
parametric_function = component[0]
|
|
1647
|
+
order = component[2]
|
|
1648
|
+
interval = intervals[i]
|
|
1649
|
+
if interval[0].lower() == -infinity:
|
|
1650
|
+
lower = interval[0].upper() - large_int
|
|
1651
|
+
upper = interval[0].upper()
|
|
1652
|
+
midpoint = upper - 0.5
|
|
1653
|
+
elif interval[0].upper() == infinity:
|
|
1654
|
+
lower = interval[0].lower()
|
|
1655
|
+
upper = interval[0].lower() + large_int
|
|
1656
|
+
midpoint = lower + 0.5
|
|
1657
|
+
else:
|
|
1658
|
+
lower = interval[0].lower()
|
|
1659
|
+
upper = interval[0].upper()
|
|
1660
|
+
midpoint = (lower+upper) / 2
|
|
1661
|
+
|
|
1662
|
+
if (lower == infinity) and (upper == infinity):
|
|
1663
|
+
midpoint = 0
|
|
1664
|
+
plot = parametric_plot(parametric_function, (var, -large_int,
|
|
1665
|
+
large_int), color='red')
|
|
1666
|
+
else:
|
|
1667
|
+
plot = parametric_plot(parametric_function, (var, lower, upper),
|
|
1668
|
+
color='red')
|
|
1669
|
+
|
|
1670
|
+
# Add the order if it is greater than or equal to 2
|
|
1671
|
+
if component[2] > 1:
|
|
1672
|
+
point = []
|
|
1673
|
+
for eq in component[0]:
|
|
1674
|
+
value = eq.subs(**{str(var): midpoint})
|
|
1675
|
+
point.append(value)
|
|
1676
|
+
text_order = text(str(order), (point[0], point[1]),
|
|
1677
|
+
fontsize=16, color='black')
|
|
1678
|
+
combined_plot += plot + text_order
|
|
1679
|
+
else:
|
|
1680
|
+
combined_plot += plot
|
|
1681
|
+
|
|
1682
|
+
# Set default axes
|
|
1683
|
+
axes = self._axes()
|
|
1684
|
+
xmin, xmax = axes[0][0], axes[0][1]
|
|
1685
|
+
ymin, ymax = axes[1][0], axes[1][1]
|
|
1686
|
+
combined_plot.set_axes_range(xmin=xmin, xmax=xmax,
|
|
1687
|
+
ymin=ymin, ymax=ymax)
|
|
1688
|
+
return combined_plot
|
|
1689
|
+
|
|
1690
|
+
def _repr_(self):
|
|
1691
|
+
"""
|
|
1692
|
+
Return a string representation of ``self``.
|
|
1693
|
+
|
|
1694
|
+
EXAMPLES::
|
|
1695
|
+
|
|
1696
|
+
sage: T = TropicalSemiring(QQ)
|
|
1697
|
+
sage: R.<x,y> = PolynomialRing(T)
|
|
1698
|
+
sage: (x^2+R(0)).tropical_variety()
|
|
1699
|
+
Tropical curve of 0*x^2 + 0
|
|
1700
|
+
"""
|
|
1701
|
+
return f"Tropical curve of {self._poly}"
|