From 6053b11b6829369e7760b8223797a49fdde4bcba Mon Sep 17 00:00:00 2001 From: Yue Ren Date: Sun, 6 Aug 2023 20:33:59 +0100 Subject: [PATCH] TropicalGeometry: major overhaul TropicalGeometry: overhaul of tropical variety types TropicalGeometry: stable intersection start TropicalGeometry: more work on different types of tropical varieties TropicalGeometry: more work on tropical varieties TropicalGeometry: generic stable intersection TropicalGeometry: Overhaul of tropical variety types TropicalGeometry: added minimal_faces TropicalGeometry: typo TropicalGeometry: fixed docu TropicalGeometry: added stable intersection linear spaces TropicalGeometry: major overhaul TropicalGeometry: curve.jl, added DocTestFilter for edges TropicalGeometry: exports.jl, removed redundant exports TropicalGeometry: curve.jl, changed DocTestFilters TropicalGeometry: Project.toml, removing RecipesBase TropicalGeometry: overhaul semiring_maps and derivatives, added docs and tests TropicalGeometry: tests for groebner_bases and initial, bug fixes TropicalGeometry: tests for hypersurface, removed redundant exports TropicalGeometry: fixed typo, uniformized formatting TropicalGeometry: removed redundant exports TropicalGeometry: Fixed typo in docs and tests TropicalGeometry: tests for varieties and bugfixes TropicalGeometry: fixing docs and tests TropicalGeometry: fixing serialization code broken by changes TropicalGeometry: improving text TropicalGeometry: uniformizing code and formatting Fix serialization TropicalGeometry: major overhaul (squashed commits) TropicalGeometry: semiring.jl, fixing doctest TropicalGeometry: Fixed Project.toml Co-authored-by: Benjamin Lorenz TropicalGeometry: Fixed Groebner bases docu Co-authored-by: Benjamin Lorenz TropicalGeometry: replaced @assert by @req Co-authored-by: Benjamin Lorenz TropicalGeometry: fixed typo in documentation Co-authored-by: Benjamin Lorenz TropicalGeometry: Improved docu Co-authored-by: Benjamin Lorenz TropicalGeometry: Replaced all @assert by @req TropicalGeometry: removed Lars and Marta from list of authors TropicalGeometry: exports.jl, fixed formatting TropicalGeometry: misc.md, deleted unnecessary file TropicalGeometry: added missing test for division by zero TropicalGeometry: undid accidental changes to Matroids/properties.jl TropicalGeometry: added missing message for @req TropicalGeometry: Added names and titles of the cited literature TropicalGeometry: fixed printing of tropical zeroes TropicalGeometry: fixed deserialisation of tropical semiring zeroes TropicalGeometry: Undoing accidental changes Co-authored-by: Benjamin Lorenz TropicalGeometry: undoing accidental changes Co-authored-by: Benjamin Lorenz remove obsolete workaround TropicalGeometry: changed multiplicities from Dict to Vector TropicalGeometry: doc and test fixes TropicalGeometry: curve.jl, fixing constructor TropicalGeometry: linear_space.jl, fixed bug in constructor TropicalGeometry: variety.jl, fixed bug in dehomogenisation --- Project.toml | 2 - docs/doc.main | 19 +- docs/oscar_references.bib | 30 + .../TropicalGeometry/curve.md | 37 - .../TropicalGeometry/intro.md | 82 -- docs/src/AlgebraicGeometry/intro.md | 1 - docs/src/TropicalGeometry/curve.md | 19 + docs/src/TropicalGeometry/groebner_theory.md | 16 + docs/src/TropicalGeometry/hypersurface.md | 25 + docs/src/TropicalGeometry/intro.md | 22 + docs/src/TropicalGeometry/linear_space.md | 31 + docs/src/TropicalGeometry/semiring.md | 32 + docs/src/TropicalGeometry/semiring_map.md | 17 + docs/src/TropicalGeometry/tropicalization.md | 14 + docs/src/TropicalGeometry/variety.md | 40 + src/Serialization/TropicalGeometry.jl | 25 +- src/TropicalGeometry/TropicalGeometry.jl | 66 +- src/TropicalGeometry/curve.jl | 947 +++++++-------- src/TropicalGeometry/groebner_basis.jl | 429 +++++-- src/TropicalGeometry/groebner_fan.jl | 6 +- src/TropicalGeometry/hypersurface.jl | 364 +++--- src/TropicalGeometry/initial.jl | 243 ++-- src/TropicalGeometry/intersection.jl | 127 ++ src/TropicalGeometry/linear_space.jl | 445 +++++-- src/TropicalGeometry/matrix.jl | 43 + src/TropicalGeometry/poly.jl | 281 ++++- src/TropicalGeometry/semiring.jl | 664 ++++------- src/TropicalGeometry/semiring_map.jl | 255 ++++ src/TropicalGeometry/tst.jl | 0 src/TropicalGeometry/valuation.jl | 464 -------- src/TropicalGeometry/variety.jl | 1030 +++++++++++------ src/TropicalGeometry/variety_supertype.jl | 617 +++------- src/exports.jl | 35 +- test/Serialization/PolynomialsSeries.jl | 6 +- test/Serialization/TropicalGeometry.jl | 64 +- test/Serialization/basic_types.jl | 8 +- test/TropicalGeometry/groebner_basis.jl | 189 +-- test/TropicalGeometry/hypersurface.jl | 14 - test/TropicalGeometry/initial.jl | 101 +- test/TropicalGeometry/matrix.jl | 11 + test/TropicalGeometry/poly.jl | 11 + test/TropicalGeometry/semiring.jl | 27 + test/TropicalGeometry/semiring_map.jl | 32 + test/TropicalGeometry/variety.jl | 44 + 44 files changed, 3673 insertions(+), 3262 deletions(-) delete mode 100644 docs/src/AlgebraicGeometry/TropicalGeometry/curve.md delete mode 100644 docs/src/AlgebraicGeometry/TropicalGeometry/intro.md create mode 100644 docs/src/TropicalGeometry/curve.md create mode 100644 docs/src/TropicalGeometry/groebner_theory.md create mode 100644 docs/src/TropicalGeometry/hypersurface.md create mode 100644 docs/src/TropicalGeometry/intro.md create mode 100644 docs/src/TropicalGeometry/linear_space.md create mode 100644 docs/src/TropicalGeometry/semiring.md create mode 100644 docs/src/TropicalGeometry/semiring_map.md create mode 100644 docs/src/TropicalGeometry/tropicalization.md create mode 100644 docs/src/TropicalGeometry/variety.md create mode 100644 src/TropicalGeometry/intersection.jl create mode 100644 src/TropicalGeometry/matrix.jl create mode 100644 src/TropicalGeometry/semiring_map.jl delete mode 100644 src/TropicalGeometry/tst.jl delete mode 100644 src/TropicalGeometry/valuation.jl delete mode 100644 test/TropicalGeometry/hypersurface.jl create mode 100644 test/TropicalGeometry/matrix.jl create mode 100644 test/TropicalGeometry/poly.jl create mode 100644 test/TropicalGeometry/semiring.jl create mode 100644 test/TropicalGeometry/semiring_map.jl create mode 100644 test/TropicalGeometry/variety.jl diff --git a/Project.toml b/Project.toml index 77ea19d04c5a..23b822fc59ea 100644 --- a/Project.toml +++ b/Project.toml @@ -18,7 +18,6 @@ Polymake = "d720cf60-89b5-51f5-aff5-213f193123e7" Preferences = "21216c6a-2e73-6563-6e65-726566657250" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RandomExtensions = "fb686558-2515-59ef-acaa-46db3789a887" -RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" Singular = "bcd08a7b-43d2-5ff7-b6d4-c458787f915c" TOPCOM_jll = "36f60fef-b880-50dc-9289-4aaecee93cc3" @@ -40,7 +39,6 @@ Polymake = "0.11.8" Preferences = "1" Random = "1.6" RandomExtensions = "0.4.3" -RecipesBase = "1.2.1" Serialization = "1.6" Singular = "0.19.0" TOPCOM_jll = "0.17.8" diff --git a/docs/doc.main b/docs/doc.main index 1267a3f45e74..54e4c50eefa7 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -134,7 +134,7 @@ "CommutativeAlgebra/ModulesOverMultivariateRings/complexes.md", ], "CommutativeAlgebra/homological_algebra.md", - + "Gröbner/Standard Bases" => [ "CommutativeAlgebra/GroebnerBases/orderings.md", "CommutativeAlgebra/GroebnerBases/groebner_bases.md", @@ -196,10 +196,6 @@ "AlgebraicGeometry/ToricVarieties/ToricIdealSheaves.md", "AlgebraicGeometry/ToricVarieties/BlowdownMorphisms.md", ], - "Tropical Geometry" => [ - "AlgebraicGeometry/TropicalGeometry/intro.md", - "AlgebraicGeometry/TropicalGeometry/curve.md", - ], "Curves" => [ "AlgebraicGeometry/Curves/AffinePlaneCurves.md", "AlgebraicGeometry/Curves/ProjectiveCurves.md", @@ -241,6 +237,19 @@ ], + "Tropical Geometry" => [ + "TropicalGeometry/intro.md", + "TropicalGeometry/semiring.md", + "TropicalGeometry/semiring_map.md", + "TropicalGeometry/variety.md", + "TropicalGeometry/hypersurface.md", + "TropicalGeometry/curve.md", + "TropicalGeometry/linear_space.md", + "TropicalGeometry/groebner_theory.md", + "TropicalGeometry/tropicalization.md", + ], + + "References" => "references.md", "Index" => "manualindex.md", "Developer Documentation" => [ diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib index c9a907b11507..c30190c1f0a1 100644 --- a/docs/oscar_references.bib +++ b/docs/oscar_references.bib @@ -233,6 +233,21 @@ @Article{BJRR12 doi = {10.1063/1.3677646} } +@Article{BJSST07, + author = {Bogart, T. and Jensen, A. N. and Speyer, D. and Sturmfels, B. and Thomas, R. R.}, + title = {Computing tropical varieties}, + zbl = {1121.14051}, + journal = {J. Symb. Comput.}, + fjournal = {Journal of Symbolic Computation}, + volume = {42}, + number = {1-2}, + pages = {54--73}, + year = {2007}, + doi = {10.1016/j.jsc.2006.02.004}, + language = {English}, + zbmath = {5203512} +} + @Article{BKR20, author = {Böhm, Janko and Keicher, Simon and Ren, Yue}, title = {Computing {GIT}-fans with symmetry and the {M}ori chamber decomposition of $\overline M_{0,6}$}, @@ -1343,6 +1358,21 @@ @Book{Loo84 year = {1984} } +@Article{MR20, + author = {Markwig, Thomas and Ren, Yue}, + title = {Computing tropical varieties over fields with valuation}, + zbl = {1445.14085}, + journal = {Found. Comput. Math.}, + fjournal = {Foundations of Computational Mathematics}, + volume = {20}, + number = {4}, + pages = {783--800}, + year = {2020}, + doi = {10.1007/s10208-019-09430-2}, + language = {English}, + zbmath = {7244216} +} + @Book{MS05, author = {Miller, Ezra and Sturmfels, Bernd}, title = {Combinatorial commutative algebra}, diff --git a/docs/src/AlgebraicGeometry/TropicalGeometry/curve.md b/docs/src/AlgebraicGeometry/TropicalGeometry/curve.md deleted file mode 100644 index cd28746fe911..000000000000 --- a/docs/src/AlgebraicGeometry/TropicalGeometry/curve.md +++ /dev/null @@ -1,37 +0,0 @@ -```@meta -CurrentModule = Oscar -``` - -# Curves - - -## Introduction - -An *abstract tropical curve* is a finite, loopless, multigraph. -It is defined by an incidence matrix with vertices as columns and edges as rows. - -A *divisor* on an abstract tropical curve is a formal linear combination of the vertices with integer coefficients. The degree of a divisor is the sum of its coefficients. A divisor is effective if all its coefficients are non-negative. - -For more definitions on the theory of divisors and linear sisyems on abstract tropical curve, we refer to [BN07](@cite). - -The *tropical Jacobian* of an abstract tropical curve is the group of divisors of degree zero modulo the subgroup of principal divisors. Here a principal divisor is the divisor associated to a piecewise-linear function on the vertices by the Laplacian operator. The tropical Jacobian is a finite abelian group, with order equal to the number of maximal spanning trees in the graph. It is isomorphic to $\prod{\mathbb{Z}/n_{i}\mathbb{Z}}$, where the $n_{i}$ are the nonzero elementary divisors of the Laplacian matrix. For more details, see [BN07](@cite). - -## Construction - -```@docs -TropicalCurve(PC::PolyhedralComplex) -DivisorOnTropicalCurve(tc::TropicalCurve, coeffs::Vector{Int}) -``` - -## Auxiliary functions -```@docs -graph(tc::TropicalCurve) -n_nodes(tc::TropicalCurve) -coefficients(dtc::DivisorOnTropicalCurve) -degree(dtc::DivisorOnTropicalCurve) -is_effective(dtc::DivisorOnTropicalCurve) -chip_firing_move(dtc::DivisorOnTropicalCurve, position::Int) -v_reduced(dtc::DivisorOnTropicalCurve, vertex::Int) -is_linearly_equivalent(dtc1::DivisorOnTropicalCurve, dtc2::DivisorOnTropicalCurve) -structure_tropical_jacobian(tc::TropicalCurve) -``` diff --git a/docs/src/AlgebraicGeometry/TropicalGeometry/intro.md b/docs/src/AlgebraicGeometry/TropicalGeometry/intro.md deleted file mode 100644 index f2a381e35f56..000000000000 --- a/docs/src/AlgebraicGeometry/TropicalGeometry/intro.md +++ /dev/null @@ -1,82 +0,0 @@ -```@meta -CurrentModule = Oscar -``` - - -# Introduction - -This page lists the OSCAR features for tropical geometry, which are still at the very beginning of their development. For notation we refer to [MS15](@cite) and [Jos21](@cite). - - -## Contact - -Please direct questions about this part of OSCAR to the following people: -* [Lars Kastner](https://lkastner.github.io/), -* [Marta Panizzut](https://martapanizzut.github.io/), -* [Yue Ren](https://www.yueren.de/). - -You can ask questions in the [OSCAR Slack](https://www.oscar-system.org/community/#slack). - -Alternatively, you can [raise an issue on github](https://www.oscar-system.org/community/#how-to-report-issues). - - -## Tropical semirings - -```@docs -TropicalSemiring -TropicalSemiringMap -tropical_polynomial -``` - - -## Tropical curves - -(no functions yet, under active development) - -```@docs -TropicalCurve -``` - -in work: chip firing, jacobians. - - -## Tropical hypersurfaces - -```@docs -TropicalHypersurface -dual_subdivision(TH::TropicalHypersurface{M, EMB}) where {M, EMB} -``` - -in work: minimal tropical polynomials of a hypersurface. - - -## Tropical linear spaces - -```@docs -TropicalLinearSpace -``` - - -## Tropical varieties - -(no functions yet, under active development) - -in work: `tropical_variety(I::MPolyIdeal,val::TropicalSemiringMap)` - - -## Groebner bases and Groebner polyhedra - -```@docs -groebner_basis(I::MPolyIdeal,val::TropicalSemiringMap,w::Vector{<: Union{Int,Rational{Int}} }; complete_reduction::Bool=false, return_lead::Bool=false) -``` - -in work: `groebner_polyhedron(I::MPolyIdeal,val::TropicalSemiringMap,w::Vector{<: Union{Int,Rational{Int}})` - - -## Intersections and stable intersections - - -```@docs -intersect(T1::TropicalVarietySupertype{M, EMB}, T2::TropicalVarietySupertype{M, EMB}) where {M, EMB} -stably_intersect(T1::TropicalVarietySupertype{M, EMB}, T2::TropicalVarietySupertype{M, EMB}) where {M, EMB} -``` diff --git a/docs/src/AlgebraicGeometry/intro.md b/docs/src/AlgebraicGeometry/intro.md index bdd63294fa05..ac9aaa0391b4 100644 --- a/docs/src/AlgebraicGeometry/intro.md +++ b/docs/src/AlgebraicGeometry/intro.md @@ -11,7 +11,6 @@ The algebraic geometry part of OSCAR provides functionality for dealing with * schemes * toric varieties, * toric schemes, -* tropical geometry. Computations in affine and projective algebraic geometry rely on [Commutative Algebra](@ref). diff --git a/docs/src/TropicalGeometry/curve.md b/docs/src/TropicalGeometry/curve.md new file mode 100644 index 000000000000..ae4538b53383 --- /dev/null +++ b/docs/src/TropicalGeometry/curve.md @@ -0,0 +1,19 @@ +```@meta +CurrentModule = Oscar +``` + +# Tropical curves + +## Introduction +A tropical curve is a graph with multiplicities on its edges. If embedded, it is a polyhedral complex of dimension (at most) one. + +## Construction +In addition to converting from `TropicalVariety`, objects of type `TropicalCurve` can be constructed from: +```@docs +``` + +## Properties +In addition to the properties inherited from `TropicalVariety`, objects of type `TropicalCurve` have the following exclusive properties: +```@docs +graph(tc::TropicalCurve) +``` diff --git a/docs/src/TropicalGeometry/groebner_theory.md b/docs/src/TropicalGeometry/groebner_theory.md new file mode 100644 index 000000000000..0d58fa8082e9 --- /dev/null +++ b/docs/src/TropicalGeometry/groebner_theory.md @@ -0,0 +1,16 @@ +# Groebner theory + +## Introduction +Groebner bases and related notions in tropical geometry are a generalization of its classical counterparts to fields with valuation. The Groebner bases take the valuation into account, the initial ideals live over the residue field, and consequently the Groebner complex is not necessarily a polyhedral fan. For details, see +- Chapter 2.4 and 2.5 in [MS15](@cite) + +## Groebner bases +```@docs +groebner_basis(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}) +``` + +## Initial forms and initial ideals +```@docs +initial(f::MPolyRingElem, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}) +initial(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}; skip_groebner_basis_computation::Bool=false) +``` diff --git a/docs/src/TropicalGeometry/hypersurface.md b/docs/src/TropicalGeometry/hypersurface.md new file mode 100644 index 000000000000..812f54c28904 --- /dev/null +++ b/docs/src/TropicalGeometry/hypersurface.md @@ -0,0 +1,25 @@ +# Tropical hypersurfaces + +## Introduction +A tropical hypersurface is a balanced polyhedral complex of codimension one. It is dual to a regular subdivision of a Newton polytope. For more on tropical hypersurfaces, see +- Chapter 3.1 in [MS15](@cite) +- Chapter 1 in [Jos21](@cite) + +Objects of type `TropicalHypersurface` need to be embedded, abstract tropical hypersurfaces are currently not supported. + +## Constructors +In addition to converting from `TropicalVariety`, objects of type `TropicalHypersurface` can be constructed from: +- polynomials over a tropical semiring, +- polynomials over a field and a tropical semiring map, +- subdivision of points and a choice of min- or max-convention. +```@docs +tropical_hypersurface +``` + +## Properties +In addition to the properties inherited from `TropicalVariety`, objects of type `TropicalHypersurface` have the following exclusive properties: +```@docs +algebraic_polynomial(TropH::TropicalHypersurface) +tropical_polynomial(TropH::TropicalHypersurface) +dual_subdivision(TropH::TropicalHypersurface) +``` diff --git a/docs/src/TropicalGeometry/intro.md b/docs/src/TropicalGeometry/intro.md new file mode 100644 index 000000000000..b16486bd967e --- /dev/null +++ b/docs/src/TropicalGeometry/intro.md @@ -0,0 +1,22 @@ +```@meta +CurrentModule = Oscar +``` + +# Introduction +The tropical geometry part of OSCAR provides functionality for +- tropical min-plus and max-plus semirings, +- matrices and polynomials thereover, +- tropical varieties, hypersurfaces, curves, and linear spaces. + + +General textbooks offering details on theory and algorithms include: +- Maclagan, Sturmfels: Introduction to Tropical Geometry [MS15](@cite) +- Joswig: Essentials of Tropical Combinatorics [Jos21](@cite) + +Like [MS15](@cite), OSCAR follows the min-convention by default and unless specified otherwise. + +## Contact +Please direct questions about this part of OSCAR to: +* [Yue Ren](https://www.yueren.de/). + +You can also ask questions in the [OSCAR Slack](https://www.oscar-system.org/community/#slack) or raise an issue on [github](https://www.oscar-system.org/community/#how-to-report-issues). diff --git a/docs/src/TropicalGeometry/linear_space.md b/docs/src/TropicalGeometry/linear_space.md new file mode 100644 index 000000000000..525390715cf8 --- /dev/null +++ b/docs/src/TropicalGeometry/linear_space.md @@ -0,0 +1,31 @@ +# Tropical linear spaces + +## Introduction +A tropical linear space is a balanced polyhedral complex supported on a finite intersection of linear tropical hypersurfaces with all multiplicities one. It is dual to a matroid subdivision of a hypersimplex, and may arise as tropicalizations of linear ideals. For more on tropical linear spaces, see +- Chapter 4.4 in [MS15](@cite) +- Chapter 10 in [Jos21](@cite) + +Objects of type `TropicalLinearSpace` need to be embedded, abstract tropical linear spaces are currently not supported. + + +## Constructors +In addition to converting from `TropicalVariety`, objects of type `TropicalLinearSpace` can be constructed from: +- Pluecker vectors over a tropical semiring, +- Pluecker vectors over a field and a tropical semiring map, +- matrices over a tropical semiring, +- matrices over a field and a tropical semiring map. +```@docs +tropical_linear_space +``` + +## Properties +In addition to the properties inherited from `TropicalVariety`, objects of type `TropicalLinearSpace` have the following exclusive properties: +```@docs +pluecker_indices(TropL::TropicalLinearSpace) +tropical_pluecker_vector(TropL::TropicalLinearSpace) +algebraic_pluecker_vector(TropL::TropicalLinearSpace) +tropical_semiring_map(TropL::TropicalLinearSpace) +tropical_matrix(TropL::TropicalLinearSpace) +algebraic_matrix(TropL::TropicalLinearSpace) +algebraic_ideal(TropL::TropicalLinearSpace) +``` diff --git a/docs/src/TropicalGeometry/semiring.md b/docs/src/TropicalGeometry/semiring.md new file mode 100644 index 000000000000..741d3e3b1e8c --- /dev/null +++ b/docs/src/TropicalGeometry/semiring.md @@ -0,0 +1,32 @@ +# Tropical semirings, matrices, and polynomials + +## Introduction +In OSCAR, the tropical semiring is either +- the min-plus semiring $(\mathbb{Q}\cup\{+\infty\},\oplus,\odot)$ with $a\oplus b=\min(a,b)$ and $a\odot b=a+b$, +- the max-plus semiring $(\mathbb{Q}\cup\{-\infty\},\oplus,\odot)$ with $a\oplus b=\max(a,b)$ and $a\odot b=a+b$. + +Whereas tropical semirings in [MS15](@cite) and [Jos21](@cite) are extensions of the real numbers, tropical semirings in OSCAR are an extension of the rational numbers to avoid precision issues. + +## Constructor +Objects of type `TropicalSemiring`, as well as matrices and polynomials thereover, can be constructed as follows: + +!!! warning + OSCAR disables unicode by default, so zeroes of tropical semirings are printed as "infty" and "-infty" instead of using their proper unicode characters. To enabled unicode in the current and future sessions, run `allow_unicode(true)`. + + +```@docs +tropical_semiring() +``` + +## Properties +Objects of type `TropicalSemiring` have the following properties: +```@docs +convention(T::TropicalSemiring{typeof(min)}) +``` + +## Related functions +Other functions related to `TropicalSemiring`, matrices, and polynomials thereover include: +```@docs +det(A::AbstractAlgebra.Generic.MatSpaceElem{<: Oscar.TropicalSemiringElem}) +tropical_polynomial(f::MPolyRingElem, nu::TropicalSemiringMap) +``` diff --git a/docs/src/TropicalGeometry/semiring_map.md b/docs/src/TropicalGeometry/semiring_map.md new file mode 100644 index 000000000000..6fff859bb1e7 --- /dev/null +++ b/docs/src/TropicalGeometry/semiring_map.md @@ -0,0 +1,17 @@ +# Tropical semiring maps + +## Introduction +In OSCAR, a `TropicalSemiringMap` is a map $\nu: K\to\mathbb{T}$ from a field $K$ to a tropical semiring $\mathbb{T}$ satisfing +1. finiteness: $\nu(a)=\pm\infty$ if and only if $a=0$, +2. multiplicativity: $\nu(a\cdot b)=\nu(a)+\nu(b)$, +3. superadditivity: $\nu(a\cdot b)\geq\min(\nu(a),\nu(b))$ (in the order defined in Section 2.7 of [Jos21](@cite)). + +Most commonly, $\nu(a)=-\mathrm{val}(a)$ if $\mathbb{T}$ is the min-plus semiring, and $\nu(a)=+\mathrm{val}(a)$ if $\mathbb{T}$ is the max-plus semiring, for some valuation $\mathrm{val}:K^\ast\rightarrow\RR$. Essentially, $\nu$ captures a valuation on $K$ as well as a choice of min- or max-convention. They are an optional input for most tropical functions over valued fields (the default being the trivial valuation and the min-convention). + +## Constructor +Tropical semiring maps can be constructed as follows: +```@docs +tropical_semiring_map(K::Field, minOrMax::Union{typeof(min),typeof(max)}=min) +tropical_semiring_map(K::QQField, p::Union{RingElem,Integer,Rational}, minOrMax::Union{typeof(min),typeof(max)}=min) +tropical_semiring_map(Kt::Generic.RationalFunctionField, t::Generic.RationalFunctionFieldElem, minOrMax::Union{typeof(min),typeof(max)}=min) +``` diff --git a/docs/src/TropicalGeometry/tropicalization.md b/docs/src/TropicalGeometry/tropicalization.md new file mode 100644 index 000000000000..d32a397e51fe --- /dev/null +++ b/docs/src/TropicalGeometry/tropicalization.md @@ -0,0 +1,14 @@ +# Tropicalization of polynomial ideals + +## Introduction +Tropical varieties can arise as tropicalizations of polynomial ideals. For a general introduction, see +- Chapter 3 in [MS15](@cite) + +For algorithmic details, see +- [BJSST07](@cite) +- [MR20](@cite) + +## Main function +```@docs +tropical_variety(I::MPolyIdeal, nu::Union{TropicalSemiringMap,Nothing}=nothing; weighted_polyhedral_complex_only::Bool=false, skip_saturation::Bool=false, skip_primary_decomposition::Bool=false) +``` diff --git a/docs/src/TropicalGeometry/variety.md b/docs/src/TropicalGeometry/variety.md new file mode 100644 index 000000000000..d09a4be9227c --- /dev/null +++ b/docs/src/TropicalGeometry/variety.md @@ -0,0 +1,40 @@ +# Tropical varieties + +## Introduction +Tropial varieties (in OSCAR) are weighted polyhedral complexes. They may arise as tropicalizations of polynomial ideals or from operations on the more specialized types of tropical varieties, such as the stable intersection of tropical hypersurfaces. For more on the first, see +- Chapter 3 in [MS15](@cite) +- Chapter 2.8 in [Jos21](@cite) + +Objects of type `TropicalVariety` need to be embedded, abstract tropical varieties are currently not supported. The type `TropicalVariety` can be thought of as supertype of `TropicalHypersurface`, `TropicalCurve`, and `TropicalLinearSpace` in the sense that the latter three inherit all properties and features of the former. + +## Constructor +Objects of type `TropicalVariety` can be constructed as follows: +```@docs +tropical_variety(Sigma::PolyhedralComplex, mult::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) +``` + +## Properties +Objects of type `TropicalVariety` (and `TropicalHypersurface`, `TropicalCurve`, `TropicalLinearSpace`) have the following properties: +```@docs +polyhedral_complex(TropV::TropicalVariety) +ambient_dim(TropV::TropicalVariety) +codim(TropV::TropicalVariety) +dim(TropV::TropicalVariety) +f_vector(TropV::TropicalVariety) +lineality_dim(TropV::TropicalVariety) +lineality_space(TropV::TropicalVariety) +maximal_polyhedra(TropV::TropicalVariety) +maximal_polyhedra_and_multiplicities(TropV::TropicalVariety) +minimal_faces(TropV::TropicalVariety) +multiplicities(TropV::TropicalVariety) +n_maximal_polyhedra(TropV::TropicalVariety) +npolyhedra(TropV::TropicalVariety) +nvertices(TropV::TropicalVariety) +is_pure(TropV::TropicalVariety) +is_simplicial(TropV::TropicalVariety) +rays(TropV::TropicalVariety) +rays_modulo_lineality(TropV::TropicalVariety) +vertices_and_rays(TropV::TropicalVariety) +vertices(TropV::TropicalVariety) +visualize(TropV::TropicalVariety) +``` diff --git a/src/Serialization/TropicalGeometry.jl b/src/Serialization/TropicalGeometry.jl index 55cca96326be..6423a3cea11d 100644 --- a/src/Serialization/TropicalGeometry.jl +++ b/src/Serialization/TropicalGeometry.jl @@ -5,14 +5,14 @@ ## elements @register_serialization_type TropicalSemiringElem uses_params -function save_type_params(s::SerializerState, x::TropicalSemiringElem) +function save_type_params(s::SerializerState, x::T) where {T <: TropicalSemiringElem} save_data_dict(s) do save_object(s, encode_type(T), :name) save_typed_object(s, parent(x), :params) end end -function load_type_params(s::DeserializerState, ::Type{<:TropicalSemiringElem}, dict::Dict) +function load_type_params(s::DeserializerState, ::Type{<:TropicalSemiringElem}, dict::Dict{Symbol, Any}) return load_typed_object(s, dict) end @@ -24,7 +24,12 @@ end function load_object(s::DeserializerState, ::Type{<:TropicalSemiringElem}, str::String, params::TropicalSemiring) - return params(load_object(s, QQFieldElem, str)) + if str == "∞" || str == "-∞" || str == "infty" || str == "-infty" + return inf(params) + else + # looks like (q) + return params(load_object(s, QQFieldElem, String(strip(str, ['(', ')'])))) + end end # Tropical Hypersurfaces @@ -32,22 +37,22 @@ end function save_object(s::SerializerState, t_surf::T) where T <: TropicalHypersurface save_data_dict(s) do - save_typed_object(s, polynomial(t_surf), :polynomial) + save_typed_object(s, tropical_polynomial(t_surf), :tropical_polynomial) end end function load_object(s::DeserializerState, ::Type{<: TropicalHypersurface}, dict::Dict) - polynomial = load_typed_object(s, dict[:polynomial]) - return TropicalHypersurface(polynomial) + polynomial = load_typed_object(s, dict[:tropical_polynomial]) + return tropical_hypersurface(polynomial) end # Tropical Curves @register_serialization_type TropicalCurve uses_id function save_object(s::SerializerState, t_curve::TropicalCurve{M, EMB}) where {M, EMB} - save_data_dict(s) do + save_data_dict(s) do if EMB - save_typed_object(s, underlying_polyhedral_complex(t_curve), :polyhedral_complex) + save_typed_object(s, polyhedral_complex(t_curve), :polyhedral_complex) save_object(s, true, :is_embedded) else save_typed_object(s, graph(t_curve), :graph) @@ -59,11 +64,11 @@ end function load_object(s::DeserializerState, ::Type{<: TropicalCurve}, dict::Dict) EMB = parse(Bool, dict[:is_embedded]) if EMB - return TropicalCurve( + return tropical_curve( load_typed_object(s, dict[:polyhedral_complex]) ) else - return TropicalCurve( + return tropical_curve( load_typed_object(s, dict[:graph]) ) end diff --git a/src/TropicalGeometry/TropicalGeometry.jl b/src/TropicalGeometry/TropicalGeometry.jl index d15c630a5b77..31601929b6a4 100644 --- a/src/TropicalGeometry/TropicalGeometry.jl +++ b/src/TropicalGeometry/TropicalGeometry.jl @@ -1,54 +1,32 @@ - -include("semiring.jl") -include("valuation.jl") -include("poly.jl") -include("initial.jl") -include("groebner_basis.jl") -include("groebner_polyhedron.jl") -include("points.jl") - -# Decompose a tropical polynomial into parts that Polymake can eat. -# First function deals with the coefficients, -# Second function then deals with the entire polynomial. -function homogenize_and_convert_to_pm(t::Oscar.TropicalSemiringElem{S}) where S<:Union{typeof(max), typeof(min)} - Add = S == typeof(max) ? Polymake.Max : Polymake.Min - if isinf(t) - return Polymake.TropicalNumber{Add}() - else - return Polymake.TropicalNumber{Add}(Polymake.new_rational_from_fmpq(data(t))) - end -end - -function homogenize_and_convert_to_pm(f::Oscar.MPolyRingElem{Oscar.TropicalSemiringElem{S}}) where S<:Union{typeof(max), typeof(min)} - Add = S == typeof(max) ? Polymake.Max : Polymake.Min - coeffs = (Polymake.TropicalNumber{Add})[] - td = total_degree(f) - exps = (Vector{Int})[] - for term in terms(f) - push!(coeffs, homogenize_and_convert_to_pm(leading_coefficient(term))) - exp = leading_exponent_vector(term) - prepend!(exp, td-sum(exp)) - push!(exps, exp) - end - exps = matrix(ZZ, exps) - coeffs = Polymake.Vector{Polymake.TropicalNumber{Add, Polymake.Rational}}(coeffs) - return coeffs, exps +############################################################################### +# +# Temporary workarounds +# +############################################################################### +function symbols(Kt::Generic.RationalFunctionField) + return Kt.S end -### -# Allow gcd of vectors of univariate rational polynomials -# to make their handling similar to that of integers -### -gcd(F::Vector{QQPolyRingElem}) = reduce(gcd, F) -gcd(F::QQPolyRingElem...) = reduce(gcd, F) - - +############################################################################### +# +# Includes +# +############################################################################### +include("semiring.jl") +include("semiring_map.jl") +include("matrix.jl") +include("poly.jl") +include("groebner_basis.jl") +include("initial.jl") +# include("groebner_polyhedron.jl") +# include("points.jl") include("variety_supertype.jl") -include("variety.jl") include("hypersurface.jl") include("curve.jl") include("linear_space.jl") +include("variety.jl") +include("intersection.jl") include("groebner_fan.jl") diff --git a/src/TropicalGeometry/curve.jl b/src/TropicalGeometry/curve.jl index 1e13671d1384..aed248bb8f33 100644 --- a/src/TropicalGeometry/curve.jl +++ b/src/TropicalGeometry/curve.jl @@ -1,536 +1,539 @@ -### -# Tropical curves in Oscar -# ======================== -### - -using RecipesBase -### -# 1. Definition -# ------------- -# M = typeof(min) or typeof(max): -# min or max convention, affecting initial ideals -# EMB = true or false: -# embedded or abstract tropical curves -# embedded tropical variety = graph embedded in euclidean space with weighted edges and vertices -# abstract tropical variety = graph with enumerated vertices with weighted edges and vertices -### - -@attributes mutable struct TropicalCurve{M,EMB} <: TropicalVarietySupertype{M,EMB} - polyhedralComplex::PolyhedralComplex - function TropicalCurve{M,EMB}(Sigma::PolyhedralComplex) where {M,EMB} - if EMB - if dim(Sigma)!=1 - error("TropicalCurve: input polyhedral complex not one-dimensional") - end - end - return new{M,EMB}(Sigma) - end -end - -function pm_object(T::TropicalCurve{M, EMB}) where {M, EMB} - if has_attribute(T,:polymake_bigobject) - return get_attribute(T,:polymake_bigobject) - end - error("pm_object(T::TropicalCurve): no polymake bigobject attributed") -end - - -### -# 2. Basic constructors -# --------------------- -### - -@doc raw""" - TropicalCurve(PC::PolyhedralComplex) - -Construct a tropical curve from a polyhedral complex. -If the curve is embedded, vertices must are points in $\mathbb R^n$. -If the curve is abstract, the polyhedral complex is empty, vertices must be 1, ..., n, -and the graph is given as attribute. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]) -3×4 IncidenceMatrix -[1, 2] -[1, 3] -[1, 4] - - -julia> VR = [0 0; 1 0; -1 0; 0 1] -4×2 Matrix{Int64}: - 0 0 - 1 0 - -1 0 - 0 1 - -julia> PC = polyhedral_complex(QQFieldElem, IM, VR) -Polyhedral complex in ambient dimension 2 - -julia> TC = TropicalCurve(PC) -min tropical curve in 2-dimensional Euclidean space - -julia> abs_TC = TropicalCurve(IM) -Abstract min tropical curve -``` -""" -function TropicalCurve(PC::PolyhedralComplex, M::Union{typeof(min),typeof(max)}=min) - @assert dim(PC)==1 "The polyhedral complex is not of dimension 1." - return TropicalCurve{M, true}(PC) -end - -function TropicalCurve(graph::IncidenceMatrix, M::Union{typeof(min),typeof(max)}=min) - # Columns correspond to nodes - # Rows correpons to edges - empty = polyhedral_complex(Polymake.fan.PolyhedralComplex()) - result = TropicalCurve{M, false}(empty) - set_attribute!(result, :graph, graph) - return result -end - -@doc raw""" - graph(tc::TropicalCurve) +############################################################################### +# +# Tropical curves +# =============== +# concrete subtype of TropicalVarietySupertype in variety_supertype.jl +# +############################################################################### -Return the graph of an abstract tropical curve `tc`. +@attributes mutable struct TropicalCurve{minOrMax,isEmbedded} <: TropicalVarietySupertype{minOrMax,isEmbedded} + polyhedralComplex::Union{PolyhedralComplex, Graph} + multiplicities::Vector{ZZRingElem} -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve + # embedded tropical curves contain a PolyhedralComplex + function TropicalCurve{minOrMax,true}(Sigma::PolyhedralComplex, multiplicities::Vector{ZZRingElem}) where {minOrMax<:Union{typeof(min),typeof(max)}} + @req dim(Sigma)==1 "input not one-dimensional" + return new{minOrMax,true}(Sigma,multiplicities) + end -julia> graph(tc) -6×4 IncidenceMatrix -[1, 2] -[1, 3] -[1, 4] -[2, 3] -[2, 4] -[3, 4] -``` -""" -function graph(tc::TropicalCurve) - @req has_attribute(tc, :graph) "No graph attached" - return get_attribute(tc, :graph) + # abstract tropical curves contain a Graph + function TropicalCurve{minOrMax,false}(Sigma::Graph, multiplicities::Vector{ZZRingElem}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return new{minOrMax,false}(Sigma,multiplicities) + end end -@doc raw""" - n_nodes(tc::TropicalCurve) - -Return the number of nodes of an abstract tropical curve `tc`. -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); -julia> tc = TropicalCurve(IM) -Abstract min tropical curve +############################################################################### +# +# Printing +# +############################################################################### -julia> n_nodes(tc) -4 -``` -""" -function n_nodes(tc::TropicalCurve) - G = graph(tc) - return Polymake.ncols(G) +function Base.show(io::IO, th::TropicalCurve{typeof(min),true}) + print(io, "Embedded min tropical curve") end - - -function Base.show(io::IO, tc::TropicalCurve{M,EMB}) where {M,EMB} - if EMB - print(io, string(M)*" tropical curve in $(ambient_dim(tc))-dimensional Euclidean space") - else - print(io, "Abstract "*string(M)*" tropical curve") - end +function Base.show(io::IO, th::TropicalCurve{typeof(max),true}) + print(io, "Embedded max tropical curve") end - -struct DivisorOnTropicalCurve{M, EMB} - base_curve::TropicalCurve{M, EMB} - coefficients::Vector{Int} - - DivisorOnTropicalCurve{M, EMB}(tc::TropicalCurve{M, EMB}, coeffs::Vector{Int}) where {M,EMB} = new{M, EMB}(tc, coeffs) +function Base.show(io::IO, th::TropicalCurve{typeof(min),false}) + print(io, "Abstract min tropical curve") end - - -@doc raw""" - DivisorOnTropicalCurve(tc::TropicalCurve, coeffs::Vector{Int}) - -Construct a divisor with coefficients `coeffs` on an abstract tropical curve `tc`. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve - -julia> coeffs = [0, 1, 1, 1]; - -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) -``` -""" -function DivisorOnTropicalCurve(tc::TropicalCurve{M, EMB}, coeffs::Vector{Int}) where {M,EMB} - if EMB - error("Not implemented yet") - end - @req n_nodes(tc) == length(coeffs) "Wrong number coefficients" - return DivisorOnTropicalCurve{M, EMB}(tc, coeffs) +function Base.show(io::IO, th::TropicalCurve{typeof(max),false}) + print(io, "Abstract max tropical curve") end -base_curve(dtc::DivisorOnTropicalCurve) = dtc.base_curve -### -# 3.Basic properties +############################################################################### +# +# Constructors # +############################################################################### + @doc raw""" - coefficients(dtc::DivisorOnTropicalCurve) + tropical_curve(Sigma::PolyhedralComplex, multiplicities::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) -Construct a divisor `dtc` with coefficients `coeffs` on an abstract tropical curve. +Return the embedded tropical curve consisting of the polyhedral complex `Sigma` and multiplicities `multiplicities`. # Examples ```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); +julia> verticesAndRays = [0 0; 1 0; 0 1; -1 -1]; -julia> tc = TropicalCurve(IM) -Abstract min tropical curve +julia> incidenceMatrix = IncidenceMatrix([[1,2],[1,3],[1,4]]); -julia> coeffs = [0, 1, 1, 1]; +julia> rayIndices = [2,3,4]; -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) +julia> Sigma = polyhedral_complex(incidenceMatrix, verticesAndRays, rayIndices) +Polyhedral complex in ambient dimension 2 -julia> coefficients(dtc) -4-element Vector{Int64}: - 0 +julia> multiplicities = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) +3-element Vector{ZZRingElem}: 1 1 1 -``` -""" -coefficients(dtc::DivisorOnTropicalCurve) = dtc.coefficients - -@doc raw""" - degree(dtc::DivisorOnTropicalCurve) - -Compute the degree of a divisor `dtc` on an abstract tropical curve. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve - -julia> coeffs = [0, 1, 1, 1]; - -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) - -julia> degree(dtc) -3 -``` -""" -degree(dtc::DivisorOnTropicalCurve) = sum(coefficients(dtc)) - -@doc raw""" - is_effective(dtc::DivisorOnTropicalCurve) - -Check whether a divisor `dtc` on an abstract tropical curve is effective. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve - -julia> coeffs = [0, 1, 1, 1]; -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) +julia> tropical_curve(Sigma,multiplicities) +Embedded min tropical curve -julia> is_effective(dtc) -true ``` """ -is_effective(dtc::DivisorOnTropicalCurve) = all(e -> e>=0, coefficients(dtc)) +function tropical_curve(Sigma::PolyhedralComplex, multiplicities::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalCurve{typeof(minOrMax),true}(Sigma,multiplicities) +end +function tropical_curve(Sigma::PolyhedralComplex, minOrMax::Union{typeof(min),typeof(max)}=min) + multiplicities = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) + return tropical_curve(Sigma,multiplicities,minOrMax) +end @doc raw""" - chip_firing_move(dtc::DivisorOnTropicalCurve, position::Int) + tropical_curve(Sigma::Graph, multiplicities::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) -Given a divisor `dtc` and vertex labelled `position`, compute the linearly equivalent divisor obtained by a chip firing move from the given vertex `position`. +Return the abstract tropical curve consisting of the graph `Sigma` and multiplicities `multiplicities`. # Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve +```jldoctest; filter = r"Edge\(.*\)" +julia> Sigma = graph_from_adjacency_matrix(Undirected,[0 1 1; 1 0 1; 1 1 0]); -julia> coeffs = [0, 1, 1, 1]; +julia> multiplicities = ones(ZZRingElem, ne(Sigma)) +3-element Vector{ZZRingElem}: + 1 + 1 + 1 -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) +julia> tropical_curve(Sigma,multiplicities) +Abstract min tropical curve -julia> chip_firing_move(dtc,1) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [-3, 2, 2, 2]) ``` """ -function chip_firing_move(dtc::DivisorOnTropicalCurve, position::Int) - G = graph(base_curve(dtc)) - newcoeffs = Vector{Int}(coefficients(dtc)) - for i in 1:Polymake.nrows(G) - row = Polymake.row(G, i) - if position in row - newcoeffs[position] -= 1 - for i in row - if i != position - newcoeffs[i] += 1 - end - end - end - end - return DivisorOnTropicalCurve(base_curve(dtc), newcoeffs) +function tropical_curve(Sigma::Graph, multiplicities::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalCurve{typeof(minOrMax), false}(Sigma,multiplicities) end - -### The function computes the outdegree of a vertex v with respect to a given subset W of vertices. -### This is the number of vertices not in W adjacent to v. 1, -function outdegree(tc::TropicalCurve, W::Set{Int}, v::Int) - G = graph(tc) - m = Polymake.nrows(G) #number of edges of tc - @assert v in W "Vertex number $v not in $W" - deg = 0 #outdeg - for i in 1:m - row = Polymake.row(G,i) - if v in row - for j in row - if !(j in W) - deg = deg +1 - end - end - end - end - return deg +function tropical_curve(Sigma::Graph,minOrMax::Union{typeof(min),typeof(max)}=min) + multiplicities = ones(ZZRingElem, ne(Sigma)) + return tropical_curve(Sigma,multiplicities,minOrMax) end -@doc raw""" - v_reduced(dtc::DivisorOnTropicalCurve, vertex::Int) -Given a divisor `dtc` and vertex labelled `vertex`, compute the unique divisor reduced with repspect to `vertex` -as defined in [BN07](@cite). -The divisor `dtc` must have positive coefficients apart from `vertex`. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); - -julia> tc = TropicalCurve(IM) -Abstract min tropical curve - -julia> coeffs = [0, 1, 1, 1]; - -julia> dtc = DivisorOnTropicalCurve(tc,coeffs) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) - -julia> v_reduced(dtc,1) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [3, 0, 0, 0]) -``` -""" -function v_reduced(dtc::DivisorOnTropicalCurve, vertex::Int) - tc = base_curve(dtc) - G = graph(base_curve(dtc)) - n = Polymake.ncols(G) - newcoeff = Vector{Int}(coefficients(dtc)) - S = Set{Int}(1:n) - W = setdiff(S,vertex) - @assert all(j -> newcoeff[j]>=0, W) "Divisor not effective outside the vertex number $vertex" - while !(isempty(W)) - w0 = vertex - if all(w -> newcoeff[w] >= outdegree(tc,W,w),W) - coeffdelta = zeros(Int, n) - delta = DivisorOnTropicalCurve(tc,coeffdelta) - for j in W - delta = chip_firing_move(delta,j) - end - newcoeff = newcoeff + coefficients(delta) - else - for w in W - if newcoeff[w] < outdegree(tc,W,w) - w0 = w - break - end - end - W = setdiff(W,w0) - end - end - reduced = DivisorOnTropicalCurve(tc, newcoeff) - return reduced +function tropical_curve(TropV::TropicalVarietySupertype) + @req dim(TropV)<=1 "tropical variety dimension too high" + return tropical_curve(polyhedral_complex(TropV), multiplicities(TropV), convention(TropV)) end -@doc raw""" - is_linearly_equivalent(dtc1::DivisorOnTropicalCurve, dtc2::DivisorOnTropicalCurve) - -Given two effective divisors `dtc1` and `dtc2` on the same tropical curve, check whether they are linearly equivalent. - -# Examples -```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); -julia> tc = TropicalCurve(IM) -Abstract min tropical curve - -julia> coeffs1 = [0, 1, 1, 1]; - -julia> dtc1 = DivisorOnTropicalCurve(tc,coeffs1) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) -julia> coeffs2 = [3,0,0,0]; +################################################################################ +# +# Properties +# +################################################################################ -julia> dtc2 = DivisorOnTropicalCurve(tc,coeffs2) -DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [3, 0, 0, 0]) +@doc raw""" + graph(TropC::TropicalCurve{minOrMax,false}) -julia> is_linearly_equivalent(dtc1, dtc2) -true -``` +Return the graph of an abstract tropical curve `TropC`. Same as `polyhedral_complex(tc)`. """ -function is_linearly_equivalent(dtc1::DivisorOnTropicalCurve, dtc2::DivisorOnTropicalCurve) - @assert is_effective(dtc1) "The divisor $dtc1 is not effective" - @assert is_effective(dtc2) "The divisor $dtc2 is not effective" - @assert base_curve(dtc1) === base_curve(dtc2) "The input curve needs to be the same for both divisors" - v = 1 - reduced1 = v_reduced(dtc1,v) - reduced2 = v_reduced(dtc2,v) - coeff1 = coefficients(reduced1) - coeff2 = coefficients(reduced2) - return coeff1 == coeff2 +function graph(TropC::TropicalCurve{minOrMax,false}) where minOrMax + return TropC.polyhedralComplex end -### -# 4. More properties -# ------------------- -### - -@doc raw""" - structure_tropical_jacobian(TC::TropicalCurve) - -Compute the elementary divisors $n_i$ of the Laplacian matrix of the tropical curve `TC`. -The tropical Jacobian is then isomorphic to $\prod (Z/(n_i)Z)$. - -# Examples -```jldoctest -julia> cg = complete_graph(5); - -julia> IM1=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg)]) -10×5 IncidenceMatrix -[1, 2] -[1, 3] -[2, 3] -[1, 4] -[2, 4] -[3, 4] -[1, 5] -[2, 5] -[3, 5] -[4, 5] - -julia> TC1 = TropicalCurve(IM1) -Abstract min tropical curve - -julia> structure_tropical_jacobian(TC1) -(General) abelian group with relation matrix -[1 0 0 0; 0 5 0 0; 0 0 5 0; 0 0 0 5] -julia> cg2 = complete_graph(3); - -julia> IM2=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg2)]) -3×3 IncidenceMatrix -[1, 2] -[1, 3] -[2, 3] - -julia> TC2 = TropicalCurve(IM2) -Abstract min tropical curve - -julia> structure_tropical_jacobian(TC2) -(General) abelian group with relation matrix -[1 0; 0 3] - -julia> IM3 = IncidenceMatrix([[1,2],[2,3],[3,4],[4,5],[1,5]]) -5×5 IncidenceMatrix -[1, 2] -[2, 3] -[3, 4] -[4, 5] -[1, 5] - -julia> TC3=TropicalCurve(IM3) -Abstract min tropical curve - -julia> G = structure_tropical_jacobian(TC3) -(General) abelian group with relation matrix -[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 5] -``` -""" -function structure_tropical_jacobian(TC::TropicalCurve) - gg=Graph{Undirected}(n_nodes(TC)) - IM = graph(TC) - for i in 1:Polymake.nrows(IM) - row = Vector{Int}(Polymake.row(IM,i)) - add_edge!(gg, row[1],row[2]) - end - lap = Polymake.graph.laplacian(Oscar.pm_object(gg)) - L = Polymake.@convert_to Matrix{Int} lap - LL = matrix(ZZ, L) - ED = elementary_divisors(LL)[1:nrows(LL)-1] - G = abelian_group(ED) - return G -end +################################################################################ +# +# Outdated code (to be updated) +# +################################################################################ -""" -This recipe allows to use `Plots` without having `Plots` as a dependency. +# @doc raw""" +# nv(tc::TropicalCurve) -Usage example: -```julia -julia> using Revise, Plots, Oscar, Test; +# Return the number of vertices of an abstract tropical curve `tc`. +# """ +# function nv(tc::TropicalCurve) +# G = graph(tc) +# return nv(G) +# end -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]); -julia> VR = [0 0; 1 0; -1 0; 0 1]; +# struct DivisorOnTropicalCurve{M, EMB} +# base_curve::TropicalCurve{M, EMB} +# coefficients::Vector{Int} -julia> PC = PolyhedralComplex{QQFieldElem}(IM, VR); +# DivisorOnTropicalCurve{M, EMB}(tc::TropicalCurve{M, EMB}, coeffs::Vector{Int}) where {M,EMB} = new{M, EMB}(tc, coeffs) +# end -julia> TC = TropicalCurve(PC); -julia> plot(TC) -``` -""" -@recipe function visualize(tc::TropicalCurve{M,EMB}) where {M,EMB} - @assert EMB "Tropical curve is abstract." - PC = tc.polyhedralComplex - MaxPoly= maximal_polyhedra(PC) - list_vertices = Vector{Complex{Float64}}() - for P in MaxPoly - V = vertices(P) - R = rays(P) - #V = [Vector{Rational{Int}}(x) for x in V] - V = [Vector{Float64}(Vector{Rational}(Vector{Polymake.Rational}(x))) for x in V] - #R = [Vector{Rational{Int}}(x) for x in R] - R = [Vector{Float64}(Vector{Rational}(Vector{Polymake.Rational}(x))) for x in R] - if length(V)==2 - append!(list_vertices,V[1][1]+V[1][2]*im,V[2][1]+V[2][2]*im,Inf+0*im) - else - B = V[1]+R[1] - append!(list_vertices,V[1][1]+V[1][2]*im,B[1]+B[2]*im,Inf+0*im) - end - end - # Set default options for plot - legend := false - axis := false - xlabel := "" - ylabel := "" - return list_vertices -end +# @doc raw""" +# divisor_on_tropical_curve(tc::TropicalCurve, coeffs::Vector{Int}) + +# Construct a divisor with coefficients `coeffs` on an abstract tropical curve `tc`. + +# # Examples +# ```jldoctest +# julia> Sigma = graph_from_adjacency_matrix(Undirected,[0 1 1 1; 1 0 1 1; 1 1 0 1; 1 1 1 0]); + +# julia> tc = tropical_curve(Sigma) +# Abstract min tropical curve + +# julia> dtc = divisor_on_tropical_curve(tc,[0, 1, 1, 1]) +# DivisorOnTropicalCurve{min, false}(Abstract min tropical curve, [0, 1, 1, 1]) +# ``` +# """ +# function divisor_on_tropical_curve(tc::TropicalCurve{minOrMax, false}, coeffs::Vector{Int}) where minOrMax +# @req nv(tc)==length(coeffs) "Wrong number coefficients" +# return DivisorOnTropicalCurve{minOrMax, false}(tc, coeffs) +# end + +# base_curve(dtc::DivisorOnTropicalCurve) = dtc.base_curve + + +# ### +# # 3.Basic properties +# ### +# @doc raw""" +# coefficients(dtc::DivisorOnTropicalCurve) + +# Return the coefficients of `dtc`. +# """ +# coefficients(dtc::DivisorOnTropicalCurve) = dtc.coefficients + + +# @doc raw""" +# degree(dtc::DivisorOnTropicalCurve) + +# Return the degree of `dtc`. +# """ +# degree(dtc::DivisorOnTropicalCurve) = sum(coefficients(dtc)) + + +# @doc raw""" +# is_effective(dtc::DivisorOnTropicalCurve) + +# Return `true` if all coefficients of `dtc` are positive, `false` otherwise. +# """ +# is_effective(dtc::DivisorOnTropicalCurve) = all(e -> e>=0, coefficients(dtc)) + + +# @doc raw""" +# chip_firing_move(dtc::DivisorOnTropicalCurve, position::Int) + +# Given a divisor `dtc` and vertex labelled `position`, compute the linearly equivalent divisor obtained by a chip firing move from the given vertex `position`. + +# # Examples +# ```jldoctest +# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); + +# julia> tc = TropicalCurve(IM) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> coeffs = [0, 1, 1, 1]; + +# julia> dtc = divisor_on_tropical_curve(tc,coeffs) +# ERROR: UndefVarError: `tc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> chip_firing_move(dtc,1) +# ERROR: UndefVarError: `dtc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 +# ``` +# """ +# function chip_firing_move(dtc::DivisorOnTropicalCurve, position::Int) +# G = graph(base_curve(dtc)) +# newcoeffs = Vector{Int}(coefficients(dtc)) +# for i in 1:ne(G) +# row = Polymake.row(incidence_matrix(G), i-1) +# if position in row +# newcoeffs[position] -= 1 +# for i in row +# if i != position +# newcoeffs[i] += 1 +# end +# end +# end +# end +# return divisor_on_tropical_curve(base_curve(dtc), newcoeffs) +# end + +# ### The function computes the outdegree of a vertex v with respect to a given subset W of vertices. +# ### This is the number of vertices not in W adjacent to v. 1, +# function outdegree(tc::TropicalCurve, W::Set{Int}, v::Int) +# G = graph(tc) +# m = ne(G) #number of edges of tc +# @req v in W "Vertex number $v not in $W" +# deg = 0 #outdeg +# for i in 1:m +# row = Polymake.row(incidence_matrix(G),i) +# if v in row +# for j in row +# if !(j in W) +# deg = deg +1 +# end +# end +# end +# end +# return deg +# end + +# @doc raw""" +# v_reduced(dtc::DivisorOnTropicalCurve, vertex::Int) + +# Given a divisor `dtc` and vertex labelled `vertex`, compute the unique divisor reduced with repspect to `vertex` +# as defined in [BN07](@cite). +# The divisor `dtc` must have positive coefficients apart from `vertex`. + +# # Examples +# ```jldoctest +# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); + +# julia> tc = TropicalCurve(IM) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> coeffs = [0, 1, 1, 1]; + +# julia> dtc = divisor_on_tropical_curve(tc,coeffs) +# ERROR: UndefVarError: `tc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> v_reduced(dtc,1) +# ERROR: UndefVarError: `dtc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 +# ``` +# """ +# function v_reduced(dtc::DivisorOnTropicalCurve, vertex::Int) +# tc = base_curve(dtc) +# G = graph(base_curve(dtc)) +# n = nv(G) +# newcoeff = Vector{Int}(coefficients(dtc)) +# S = Set{Int}(1:n) +# W = setdiff(S,vertex) +# @req all(j -> newcoeff[j]>=0, W) "Divisor not effective outside the vertex number $vertex" +# while !(isempty(W)) +# w0 = vertex +# if all(w -> newcoeff[w] >= outdegree(tc,W,w),W) +# coeffdelta = zeros(Int, n) +# delta = divisor_on_tropical_curve(tc,coeffdelta) +# for j in W +# delta = chip_firing_move(delta,j) +# end +# newcoeff = newcoeff + coefficients(delta) +# else +# for w in W +# if newcoeff[w] < outdegree(tc,W,w) +# w0 = w +# break +# end +# end +# W = setdiff(W,w0) +# end +# end +# reduced = divisor_on_tropical_curve(tc, newcoeff) +# return reduced +# end + +# @doc raw""" +# is_linearly_equivalent(dtc1::DivisorOnTropicalCurve, dtc2::DivisorOnTropicalCurve) + +# Given two effective divisors `dtc1` and `dtc2` on the same tropical curve, check whether they are linearly equivalent. + +# # Examples +# ```jldoctest +# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]); + +# julia> tc = TropicalCurve(IM) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> coeffs1 = [0, 1, 1, 1]; + +# julia> dtc1 = divisor_on_tropical_curve(tc,coeffs1) +# ERROR: UndefVarError: `tc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> coeffs2 = [3,0,0,0]; + +# julia> dtc2 = divisor_on_tropical_curve(tc,coeffs2) +# ERROR: UndefVarError: `tc` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> is_linearly_equivalent(dtc1, dtc2) +# ERROR: UndefVarError: `dtc1` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 +# ``` +# """ +# function is_linearly_equivalent(dtc1::DivisorOnTropicalCurve, dtc2::DivisorOnTropicalCurve) +# @req is_effective(dtc1) "The divisor $dtc1 is not effective" +# @req is_effective(dtc2) "The divisor $dtc2 is not effective" +# @req base_curve(dtc1) === base_curve(dtc2) "The input curve needs to be the same for both divisors" +# v = 1 +# reduced1 = v_reduced(dtc1,v) +# reduced2 = v_reduced(dtc2,v) +# coeff1 = coefficients(reduced1) +# coeff2 = coefficients(reduced2) +# return coeff1 == coeff2 +# end + + +# ### +# # 4. More properties +# # ------------------- +# ### + +# @doc raw""" +# structure_tropical_jacobian(TropC::TropicalCurve) + +# Compute the elementary divisors $n_i$ of the Laplacian matrix of the tropical curve `TropC`. +# The tropical Jacobian is then isomorphic to $\prod (Z/(n_i)Z)$. + +# # Examples +# ```jldoctest +# julia> cg = complete_graph(5); + +# julia> IM1=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg)]) +# 10×5 IncidenceMatrix +# [1, 2] +# [1, 3] +# [2, 3] +# [1, 4] +# [2, 4] +# [3, 4] +# [1, 5] +# [2, 5] +# [3, 5] +# [4, 5] + +# julia> TropC1 = TropicalCurve(IM1) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> structure_tropical_jacobian(TropC1) +# ERROR: UndefVarError: `TropC1` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> cg2 = complete_graph(3); + +# julia> IM2=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg2)]) +# 3×3 IncidenceMatrix +# [1, 2] +# [1, 3] +# [2, 3] + +# julia> TropC2 = TropicalCurve(IM2) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> structure_tropical_jacobian(TropC2) +# ERROR: UndefVarError: `TropC2` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> IM3 = IncidenceMatrix([[1,2],[2,3],[3,4],[4,5],[1,5]]) +# 5×5 IncidenceMatrix +# [1, 2] +# [2, 3] +# [3, 4] +# [4, 5] +# [1, 5] + +# julia> TropC3=TropicalCurve(IM3) +# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric}) +# Stacktrace: +# [1] top-level scope +# @ none:1 + +# julia> G = structure_tropical_jacobian(TropC3) +# ERROR: UndefVarError: `TropC3` not defined +# Stacktrace: +# [1] top-level scope +# @ none:1 +# ``` +# """ +# function structure_tropical_jacobian(TropC::TropicalCurve) +# gg=Graph{Undirected}(nv(TropC)) +# IM = graph(TropC) +# for i in 1:ne(IM) +# row = Vector{Int}(Polymake.row(incidence_matrix(IM),i)) +# add_edge!(gg, row[1],row[2]) +# end +# lap = Polymake.graph.laplacian(Oscar.pm_object(gg)) +# L = Polymake.@convert_to Matrix{Int} lap +# LL = matrix(ZZ, L) +# ED = elementary_divisors(LL)[1:nrows(LL)-1] +# G = abelian_group(ED) +# return G +# end + + +# # """ +# # This recipe allows to use `Plots` without having `Plots` as a dependency. + +# # Usage example: +# # ```julia +# # julia> using Revise, Plots, Oscar, Test; + +# # julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]); + +# # julia> VR = [0 0; 1 0; -1 0; 0 1]; + +# # julia> PC = PolyhedralComplex{QQFieldElem}(IM, VR); + +# # julia> TropC = TropicalCurve(PC); + +# # julia> plot(TropC) +# # ``` +# # """ +# # @recipe function visualize(tc::TropicalCurve{M,EMB}) where {M,EMB} +# # @req EMB "Tropical curve is abstract." +# # PC = tc.polyhedralComplex +# # MaxPoly= maximal_polyhedra(PC) +# # list_vertices = Vector{Complex{Float64}}() +# # for P in MaxPoly +# # V = vertices(P) +# # R = rays(P) +# # #V = [Vector{Rational{Int}}(x) for x in V] +# # V = [Vector{Float64}(Vector{Rational}(Vector{Polymake.Rational}(x))) for x in V] +# # #R = [Vector{Rational{Int}}(x) for x in R] +# # R = [Vector{Float64}(Vector{Rational}(Vector{Polymake.Rational}(x))) for x in R] +# # if length(V)==2 +# # append!(list_vertices,V[1][1]+V[1][2]*im,V[2][1]+V[2][2]*im,Inf+0*im) +# # else +# # B = V[1]+R[1] +# # append!(list_vertices,V[1][1]+V[1][2]*im,B[1]+B[2]*im,Inf+0*im) +# # end +# # end +# # # Set default options for plot +# # legend := false +# # axis := false +# # xlabel := "" +# # ylabel := "" +# # return list_vertices +# # end diff --git a/src/TropicalGeometry/groebner_basis.jl b/src/TropicalGeometry/groebner_basis.jl index de9be25b830d..3f5a60be6786 100644 --- a/src/TropicalGeometry/groebner_basis.jl +++ b/src/TropicalGeometry/groebner_basis.jl @@ -1,122 +1,363 @@ -### -# Computing (tropical) Groebner bases in Oscar -# ============================================ +################################################################################ # -# For a definition of tropical Groebner basis see Section 2.4 in: -# D. Maclagan, B. Sturmfels: Introduction to tropical geometry -# To see how they can be computed using standard bases see: -# T. Markwig, Y. Ren: Computing tropical varieties over fields with valuation -### +# Tropical Groebner bases +# ======================= +# +# For a definition of tropical Groebner basis see Section 2.4 in: +# D. Maclagan, B. Sturmfels: Introduction to tropical geometry +# To see how they can be computed using standard bases see: +# T. Markwig, Y. Ren: Computing tropical varieties over fields with valuation +# +################################################################################ + + + +################################################################################ +# +# Simulating and desimulating valuations +# +################################################################################ +@doc raw""" + simulate_valuation(I::MPolyIdeal, nu::TropicalSemiringMap) +Given an ideal `I` in variables x1, ..., xn over a field with a tropical semiring map `nu`, return an ideal `sI` in variables tsim, x1, ..., xn such that tropical Groebner bases of `I` with respect to a weight vectors `w` correspond to standard bases of `sI` with respect to `(-1,-w)` (min-convention) or `(-1,w)` (max-convention). +# Example ($p$-adic) +```jldoctest +julia> nu_2 = tropical_semiring_map(QQ,2); + +julia> Kx,(x1,x2,x3) = polynomial_ring(QQ,3); + +julia> I = ideal([x1+2*x2,x2+2*x3]); + +julia> simulate_valuation(I,nu_2) +ideal(-tsim + 2, tsim*x2 + x1, tsim*x3 + x2) + +``` + +# Example ($t$-adic) +```jldoctest +julia> K,s = rational_function_field(GF(2),"s"); -#======= -returns true if I has homogeneous generators, -returns false otherwise -=======# -function _has_homogeneous_generators(I::MPolyIdeal{K} where {K}) - # todo: replace with function that properly tests whether ideal is homogeneous - # this requires interreduction which is not available in Oscar yet - return all(_is_homogeneous, gens(I)) +julia> nu_s = tropical_semiring_map(K,s); + +julia> s = Oscar.valued_ring(nu_s)(s); + +julia> Kx,(x1,x2,x3) = polynomial_ring(K,3); + +julia> I = ideal([x1+s*x2,x2+s*x3]); + +julia> simulate_valuation(I,nu_s) +ideal(tsim + s, tsim*x2 + x1, tsim*x3 + x2) + +``` +""" +function simulate_valuation(I::MPolyIdeal, nu::TropicalSemiringMap) + @req !isempty(gens(I)) "input ideal empty" + + R = valued_ring(nu) + Rtx,tx = polynomial_ring(R,vcat([:tsim],symbols(base_ring(I)))) + + sG = [R(uniformizer(nu))-tx[1]] + for f in clear_coefficient_denominators.(gens(I)) + fRtx = MPolyBuildCtx(Rtx) + for (cK,expvKx) = zip(coefficients(f),exponents(f)) + cR = numerator(cK) # coefficient in R + expvRtx = vcat([0],expvKx) # exponent vector in R[t,x1,...,xn] + push_term!(fRtx,cR,expvRtx) + end + push!(sG,tighten_simulation(finish(fRtx),nu)) + end + + return ideal(Rtx,sG) +end +function clear_coefficient_denominators(f::MPolyRingElem) + return lcm(denominator.(coefficients(f)))*f +end +# if valuation trivial, do nothing +function simulate_valuation(I::MPolyIdeal, nu::TropicalSemiringMap{K,Nothing,<:Union{typeof(min),typeof(max)}}) where {K} + return I end @doc raw""" - groebner_basis(I::Ideal, val::TropicalSemiringMap, w::Vector; complete_reduction::Bool, return_lead::Bool) + tighten_simulation(f::MPolyRingElem, nu::TropicalSemiringMap) -Compute a Groebner basis of `I` over a field with valuation `val` with respect -to weight vector `w`, that is a finite generating set of `I` whose initial forms -generate the initial ideal with respect to `w`. +Given a polynomial `f` in the simulation ring, "replace" the uniformizer with the first variable `tsim`, and divide by the gcd of all coefficients and the highest possible power of `tsim`. The result is a polynomial whose coefficient valuations have been encoded in the exponents of `tsim`. -For the definitions of initial form, initial ideal and Groebner basis see -Section 2.4 of [MS15](@cite). +# Example ($p$-adic) +```jldoctest +julia> nu_2 = tropical_semiring_map(QQ,2) +Map into Min tropical semiring encoding the 2-adic valuation on Rational field -!!! warning - Groebner bases over fields with valuation are still in an experimental stage. - `I` must be generated by homogeneous polynomials and `val` must be non-trivial. +julia> Rtx,(p,x1,x2,x3) = Oscar.valued_ring(nu_2)["p","x1","x2","x3"] +(Multivariate polynomial ring in 4 variables over ZZ, ZZMPolyRingElem[p, x1, x2, x3]) -# Examples +julia> f = x1+p*x1+p^2*x1+2^2*x2+p*x2+p^2*x2+x3 +p^2*x1 + p^2*x2 + p*x1 + p*x2 + x1 + 4*x2 + x3 + +julia> Oscar.tighten_simulation(f,nu_2) +5*p*x2 + 7*x1 + x3 + +julia> Oscar.tighten_simulation(2^3*f,nu_2) +5*p*x2 + 7*x1 + x3 + +julia> Oscar.tighten_simulation(p^3*f,nu_2) +5*p*x2 + 7*x1 + x3 + +``` + +# Example ($t$-adic) ```jldoctest -julia> R,(x,y) = polynomial_ring(QQ,["x","y"]); +julia> K,s = rational_function_field(GF(2),"s"); -julia> I = ideal([x^3-5*x^2*y,3*y^3-2*x^2*y]) -ideal(x^3 - 5*x^2*y, -2*x^2*y + 3*y^3) +julia> nu_s = tropical_semiring_map(K,s); -julia> val_2 = TropicalSemiringMap(QQ,2); +julia> s = Oscar.valued_ring(nu_s)(s); -julia> w = [0,0]; +julia> Rtx,(t,x1,x2,x3) = Oscar.valued_ring(nu_s)["t","x1","x2","x3"]; + +julia> f = x1+t*x1+t^2*x1+s^2*x2+t*x2+t^2*x2+x3 +t^2*x1 + t^2*x2 + t*x1 + t*x2 + x1 + s^2*x2 + x3 + +julia> Oscar.tighten_simulation(f,nu_s) +t*x2 + (s^2 + s + 1)*x1 + x3 + +julia> Oscar.tighten_simulation(s^3*f,nu_s) +t*x2 + (s^2 + s + 1)*x1 + x3 + +julia> Oscar.tighten_simulation(t^3*f,nu_s) +t*x2 + (s^2 + s + 1)*x1 + x3 -julia> groebner_basis(I,val_2,w) -5-element Vector{QQMPolyRingElem}: - 2*x^2*y - 3*y^3 - x^3 - 5*x^2*y - x*y^3 - 5*y^4 - y^5 - x^2*y^3 + 69*y^5 ``` """ -function groebner_basis(I::MPolyIdeal,val::TropicalSemiringMap,w::Vector{<: Union{Int,Rational{Int}} }; complete_reduction::Bool=false, return_lead::Bool=false) - - @assert Oscar._has_homogeneous_generators(I) - - ### - # Step 1: Compute a standard basis in the simulation ring - ### - vvI = simulate_valuation(I,val) - w = simulate_valuation(w,val) - Rtx = base_ring(vvI) - # todo: replace with groebner_bases in OSCAR once more orderings are supported - S,_ = Singular.polynomial_ring(singular_coeff_ring(base_ring(Rtx)), symbols(Rtx); ordering = Singular.ordering_a(w)*Singular.ordering_dp()) - SI = Singular.Ideal(S, [S(g) for g in gens(vvI)]) - vvGB = Singular.gens(Singular.std(SI,complete_reduction=complete_reduction)) - - - ### - # Step 2: tighten simulation so that no two monomials of the standard basis - # elements have the same x-monomial - ### - vvGB = [S(tighten_simulation(Rtx(g),val)) for g in vvGB] - - - ### - # Step 3: if complete_reduction = true and val is non-trivial, eliminate - # tail-monomials contained in the leading ideal in the tropical sense - # In the simulation, these monomials corresponds to tail-monomials contained - # in the leading ideal up to saturation by t and elimination means - # eliminating them after multiplying by a sufficiently high power in t - ### - if complete_reduction==true && is_valuation_nontrivial(val) - sort!(vvGB,lt=_x_monomial_lt) # sort vvGB by their leading x monomial from small to large - Singular.libSingular.set_option("OPT_INFREDTAIL", true) - for i in 1:length(vvGB)-1 - for j in i+1:length(vvGB) - vvGB[j] = Singular.reduce(vvGB[j],Singular.std(Singular.Ideal(S,vvGB[i]))) - end +function tighten_simulation(f::MPolyRingElem, nu::TropicalSemiringMap) + # substitute first variable tsim by uniformizer_ring + # so that all monomials have distinct x-monomials + f = evaluate(f,[1],[uniformizer(nu)]) + + # divide f by the gcd of its coefficients + f /= gcd(collect(coefficients(f))) + + # undo previous substitution by replace uniformizer with first variable + sf = MPolyBuildCtx(parent(f)) + for (c,alpha) in zip(coefficients(f),exponents(f)) + d = Int(nu(c); preserve_ordering=true) + c /= uniformizer(nu)^d # divide uniformizer out of coefficient + alpha[1] += d # increase exponent in tsim instead + push_term!(sf,c,alpha) end - Singular.libSingular.set_option("OPT_INFREDTAIL", false) - end + return finish(sf) +end +# if valuation trivial, do nothing +function tighten_simulation(f::MPolyRingElem, nu::TropicalSemiringMap{K,Nothing,minOrMax}) where {K<:Field, minOrMax<:Union{typeof(min),typeof(max)}} + return f +end - GB = desimulate_valuation(ideal(Rtx,vvGB),val) - if return_lead - vvLI = Singular.lead(vvGB) - LI = desimulate_valuation(ideal(Rtx,Singular.gens(vvLI)),val) - return gens(GB),gens(LI) - end - return gens(GB) + +@doc raw""" + simulate_valuation(w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}, nu::TropicalSemiringMap{K,p,<:Union{typeof(min),typeof(max)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + +Return an integer vector `wSim` so that the (tropical) Groebner basis of an ideal `I` with respect to `w` corresponds to the standard basis of its simulation with respect to `wSim`. If `pertubation!=nothing`, also returns a corresponding `perturbationSim`. + +# Example +```jldoctest +julia> nuMin = tropical_semiring_map(QQ,2); + +julia> nuMax = tropical_semiring_map(QQ,2,max); + +julia> w = QQ.([1,1]); + +julia> u = QQ.([1,0]); + +julia> simulate_valuation(w,nuMin;perturbation=u) +(QQFieldElem[-1, -1, -1], QQFieldElem[0, -1, 0]) + +julia> simulate_valuation(w,nuMax;perturbation=u) +(QQFieldElem[-1, 1, 1], [0, 1, 0]) + +``` +""" +function simulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,p,typeof(min)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + w = vcat([one(QQ)],w) # prepend +1 to the vector + w .*= -lcm(denominator.(w)) # scale vector to make entries integral + # negate vector to convert to max convention for Singular + if !isnothing(perturbation) + perturbation = vcat([0],perturbation) + perturbation .*= -lcm(denominator.(perturbation)) + return w, perturbation + end + return w end +function simulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,p,typeof(max)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + w = vcat([-one(QQ)],w) # prepend -1 to the vector + w .*= lcm(denominator.(w)) # scale vector to make entries integral + if !isnothing(perturbation) + perturbation = vcat([0],perturbation) + perturbation .*= lcm(denominator.(perturbation)) + perturbation = Int.(perturbation) + return w, perturbation + end + return w +end +# if valuation is trivial, just flip sign depending on convention +function simulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,Nothing,typeof(min)}; perturbation::Union{Nothing,Vector}=nothing) where {K} + isnothing(perturbation) ? (return -w) : (return -w, -perturbation) +end +function simulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,Nothing,typeof(max)}; perturbation::Union{Nothing,Vector}=nothing) where {K} + isnothing(perturbation) ? (return w) : (return w,perturbation) +end + + + +@doc raw""" + desimulate_valuation(sG::Vector{<:MPolyRingElem}, nu::TropicalSemiringMap) + +Given a generating set of the simulation ideal, reconstruct a generating set of the original ideal. In pparticular, given a standard basis of the simulation ideal with respect to `wSim`, return the (tropical) Groebner basis of the original ideal with respect to `w`. + +# Example ($p$-adic) +```jldoctest +julia> nu_2 = tropical_semiring_map(QQ,2); + +julia> Kx,(x1,x2,x3) = polynomial_ring(QQ,3); + +julia> I = ideal(Kx,[x1+2*x2,x2+2*x3]) +ideal(x1 + 2*x2, x2 + 2*x3) + +julia> sG = gens(simulate_valuation(I,nu_2)) +3-element Vector{ZZMPolyRingElem}: + -tsim + 2 + tsim*x2 + x1 + tsim*x3 + x2 + +julia> desimulate_valuation(sG,nu_2) +2-element Vector{QQMPolyRingElem}: + x1 + 2*x2 + x2 + 2*x3 + +``` +""" +function desimulate_valuation(sG::Vector{<:MPolyRingElem}, nu::TropicalSemiringMap) + # construct original polynomial ring over valued field + Rtx = parent(first(sG)) + xSymbols = copy(symbols(Rtx))[2:end] + K = valued_field(nu) + Kx,x = polynomial_ring(K,xSymbols) + + # map everything from simulation ring to original polynomial ring + # whilst substituting first variable tsim by uniformizer + desimulation_map = hom(Rtx,Kx,c->K(c),vcat(Kx(uniformizer(nu)),x)) + G = desimulation_map.(sG) + return G[findall(!iszero,G)] # return only non-zero elements +end +# if valuation trivial, do nothing +function desimulate_valuation(sG::Vector{<:MPolyRingElem}, nu::TropicalSemiringMap{K,Nothing,minOrMax}) where {K,minOrMax<:Union{typeof(min),typeof(max)}} + return sG +end + + + +@doc raw""" + desimulate_valuation(w::Vector, nu::TropicalSemiringMap{K,p,typeof(min)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + +Given a weight vector `wSim` on the simulation ring, return weight vector `w` on the original polynomial ring so that a standard basis with respect to `wSim` corresponds to a (tropical) Groebner basis with respect to `w`. + +# Example +```jldoctest +julia> nuMin = tropical_semiring_map(QQ,2); + +julia> nuMax = tropical_semiring_map(QQ,2,max); + +julia> w = QQ.([1,1]); + +julia> u = QQ.([1,0]); + +julia> wSim, uSim = simulate_valuation(w,nuMin;perturbation=u) +(QQFieldElem[-1, -1, -1], QQFieldElem[0, -1, 0]) +julia> desimulate_valuation(wSim, nuMin; perturbation=uSim) +(QQFieldElem[1, 1], QQFieldElem[1, 0]) +julia> wSim, uSim = simulate_valuation(w,nuMax;perturbation=u) +(QQFieldElem[-1, 1, 1], [0, 1, 0]) -#======= -returns true if the leading x-monomial of f is less than that of g, -returns false otherwise -=======# -function _x_monomial_lt(f::Singular.spoly,g::Singular.spoly) - expv_f = copy(Singular.leading_exponent_vector(f)) - expv_g = copy(Singular.leading_exponent_vector(g)) - popfirst!(expv_f) - popfirst!(expv_g) - return expv_f desimulate_valuation(wSim, nuMax; perturbation=uSim) +(QQFieldElem[1, 1], [1, 0]) + +``` +""" +function desimulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,p,typeof(min)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + @req w[1]<0 "invalid weight vector" + # scale the vector so that first entry is 1, then remove first entry + w ./= w[1] + if !isnothing(perturbation) + # negate vector, then remove first entry + perturbation *= -1 + return w[2:end],perturbation[2:end] + end + return w[2:end] +end +function desimulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,p,typeof(max)}; perturbation::Union{Nothing,Vector}=nothing) where {K,p} + @req w[1]<0 "invalid weight vector" + # scale the vector so that first entry is -1, then remove first entry + w ./= -w[1] + if !isnothing(perturbation) + # remove first entry + return w[2:end],perturbation[2:end] + end + return w[2:end] +end +# if trivial valuation, just flip sign depending on convention +function desimulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,Nothing,typeof(min)}; perturbation::Union{Nothing,Vector}=nothing) where {K} + isnothing(perturbation) ? (return -w) : (return -w,-perturbation) +end +function desimulate_valuation(w::Vector{QQFieldElem}, nu::TropicalSemiringMap{K,Nothing,typeof(max)}; perturbation::Union{Nothing,Vector}=nothing) where {K} + isnothing(perturbation) ? (return w) : (return w,perturbation) +end + + + +################################################################################ +# +# (Tropical) Groebner bases +# +################################################################################ +@doc raw""" + groebner_basis(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}) + +Return a (tropical) Groebner basis of `I` with respect to the tropical semiring map `nu` and weight vector `w`, that is a finite generating set of `I` whose initial forms with respect to `nu` and `w` generate the initial ideal. + +For the definitions of initial form, initial ideal and Groebner basis see Section 2.4 of [MS15](@cite). + +!!! warning + Groebner bases over fields with valuation are still in an experimental stage. If `nu` is non-trivial, then `I` must be generated by homogeneous polynomials. + +# Examples +```jldoctest +julia> R,(x,y) = QQ["x","y"]; + +julia> I = ideal([x^3-5*x^2*y,3*y^3-2*x^2*y]); + +julia> nu = tropical_semiring_map(QQ,2); + +julia> w = QQ.([0,0]); + +julia> groebner_basis(I,nu,w) +2-element Vector{QQMPolyRingElem}: + x^3 - 5*x^2*y + -2*x^2*y + 3*y^3 + +``` +""" +function groebner_basis(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}) + @req all(Oscar._is_homogeneous, gens(I)) "input ideal needs homogeneous generators" + Isim = simulate_valuation(I,nu) + wSim = simulate_valuation(QQ.(w),nu) + # TODO: experiment with different tiebreaker orderings + oSim = weight_ordering(Int.(wSim),default_ordering(base_ring(Isim))) + Gsim = standard_basis(Isim; ordering = oSim) + G = desimulate_valuation(gens(Gsim),nu) + return G end diff --git a/src/TropicalGeometry/groebner_fan.jl b/src/TropicalGeometry/groebner_fan.jl index 0a54f22f96b2..05a7cac28936 100644 --- a/src/TropicalGeometry/groebner_fan.jl +++ b/src/TropicalGeometry/groebner_fan.jl @@ -181,7 +181,7 @@ julia> rays_modulo_lineality(maximal_groebner_cone(G)) ``` """ function maximal_groebner_cone(G::Oscar.IdealGens{<:MPolyRingElem}) - @assert is_groebner_basis(G) + @req is_groebner_basis(G) "input not a Groebner basis" ord = ordering(G) G = collect(G) homogeneityWeight = homogeneity_vector(G) @@ -189,7 +189,7 @@ function maximal_groebner_cone(G::Oscar.IdealGens{<:MPolyRingElem}) end function maximal_groebner_cone(G::Oscar.IdealGens{<:MPolyRingElem}, homogeneityWeight::Union{Vector{ZZRingElem},Nothing}) - @assert is_groebner_basis(G) + @req is_groebner_basis(G) "input not a Groebner basis" ord = ordering(G) G = collect(G) return maximal_groebner_cone(G,ord,homogeneityWeight) @@ -407,7 +407,7 @@ If `I` is not weighted homogeneous with respect to a positive weight vector, the If `return_groebner_bases==true`, also return a dictionary whose keys are interior points of the maximal cones and whose values are the Groebner bases for those cones. Their union will be a universal Groebner basis. -If `return_orderings==true`, returns a dictionary whose keys are interior points of the maximal Groebner cones and whose values are monomial orderings for those cones. These orderings are suboptimal and hence it is generally recommended to create new orderings with the interior points. However they do contain information on how the fan was traversed. +If `return_orderings==true`, also return a dictionary whose keys are interior points of the maximal Groebner cones and whose values are monomial orderings for those cones. These orderings are suboptimal and hence it is generally recommended to create new orderings with the interior points. However they do contain information on how the fan was traversed. # Examples ```jldoctest diff --git a/src/TropicalGeometry/hypersurface.jl b/src/TropicalGeometry/hypersurface.jl index b106ccad4b82..a1045642099a 100644 --- a/src/TropicalGeometry/hypersurface.jl +++ b/src/TropicalGeometry/hypersurface.jl @@ -1,278 +1,264 @@ -### -# Tropical hypersurfaces in Oscar -### - -################################################################################ +############################################################################### # -# Definition +# Tropical hypersurfaces +# ====================== +# concrete subtype of TropicalVarietySupertype in variety_supertype.jl # -################################################################################ +############################################################################### -# We use M to record whether we are in the min/max case -# M is either typeof(min) or typeof(max) -# We use EMB to record whether the hypersurface is embedded or abstract -# EMB is either true or false: -# embedded tropical variety = weighted polyhedral complex in euclidean space -# abstract tropical variety = weighted hypergraph with enumerated vertices - -@attributes mutable struct TropicalHypersurface{M,EMB} <: TropicalVarietySupertype{M,EMB} +@attributes mutable struct TropicalHypersurface{minOrMax,isEmbedded} <: TropicalVarietySupertype{minOrMax,isEmbedded} polyhedralComplex::PolyhedralComplex - function TropicalHypersurface{M,EMB}(Sigma::PolyhedralComplex) where {M,EMB} - if codim(Sigma)!=1 - error("TropicalHypersurface: input polyhedral complex not one-codimensional") - end - return new{M,EMB}(Sigma) - end -end + multiplicities::Vector{ZZRingElem} -function pm_object(T::TropicalHypersurface) - if has_attribute(T,:polymake_bigobject) - return get_attribute(T,:polymake_bigobject) + # tropical hypersurfaces need to be embedded + function TropicalHypersurface{minOrMax,true}(Sigma::PolyhedralComplex, multiplicities::Vector{ZZRingElem}) where {minOrMax<:Union{typeof(min),typeof(max)}} + @req codim(Sigma)==1 "input polyhedral complex not one-codimensional" + return new{minOrMax,true}(Sigma,multiplicities) end - error("pm_object(T::TropicalHypersurface): Has no polymake bigobject") end + + ################################################################################ # # Printing # ################################################################################ - -function Base.show(io::IO, th::TropicalHypersurface{M, EMB}) where {M, EMB} - if EMB - print(io, "$(repr(M)) tropical hypersurface embedded in $(ambient_dim(th))-dimensional Euclidean space") - else - print(io, "Abstract $(repr(M)) tropical hypersurface of dimension $(dim(th))") - end +function Base.show(io::IO, th::TropicalHypersurface{typeof(min),true}) + print(io, "Min tropical hypersurface") end +function Base.show(io::IO, th::TropicalHypersurface{typeof(max),true}) + print(io, "Max tropical hypersurface") +end + + ################################################################################ # -# Constructors for tropical hypersurfaces +# Constructors # ################################################################################ +function tropical_hypersurface(Sigma::PolyhedralComplex, mult::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalHypersurface{typeof(minOrMax),true}(Sigma,mult) +end + + +function tropical_hypersurface(TropV::TropicalVarietySupertype{minOrMax,true}) where {minOrMax<:Union{typeof(max), typeof(min)}} + @req codim(TropV)==1 "tropical variety codimension not one" + @req is_pure(TropV) "tropical variety not pure" + return tropical_hypersurface(polyhedral_complex(TropV),multiplicities(TropV),convention(TropV)) +end + +# Decompose a tropical polynomial into parts that Polymake can eat. +# First function deals with the coefficients, +# Second function then deals with the entire polynomial. +function homogenize_and_convert_to_pm(t::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(max), typeof(min)}} + Add = (minOrMax==typeof(max)) ? Polymake.Max : Polymake.Min + if isinf(t) + return Polymake.TropicalNumber{Add}() + else + return Polymake.TropicalNumber{Add}(Polymake.new_rational_from_fmpq(data(t))) + end +end + +function homogenize_and_convert_to_pm(f::Oscar.MPolyRingElem{TropicalSemiringElem{minOrMax}}) where {minOrMax<:Union{typeof(max), typeof(min)}} + Add = (minOrMax==typeof(max)) ? Polymake.Max : Polymake.Min + coeffs = Polymake.TropicalNumber{Add}[] + td = total_degree(f) + exps = Vector{Int}[] + for (c,alpha) in zip(coefficients(f),exponents(f)) + push!(coeffs, homogenize_and_convert_to_pm(c)) + prepend!(alpha, td-sum(alpha)) + push!(exps, alpha) + end + exps = matrix(ZZ, exps) + coeffs = Polymake.Vector{Polymake.TropicalNumber{Add, Polymake.Rational}}(coeffs) + return coeffs, exps +end + @doc raw""" - TropicalHypersurface(f::AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{T}}) + tropical_hypersurface(f::MPolyRingElem{<:TropicalSemiringElem}, weighted_polyhedral_complex_only::Bool=false) -Return the tropical hypersurface of a tropical polynomial `f`. +Return the tropical hypersurface of the tropical polynomial `f`. If `weighted_polyhedral_complex==true`, will not cache any extra information. # Examples ```jldoctest -julia> T = TropicalSemiring(min) -Tropical semiring (min) +julia> T = tropical_semiring() +Min tropical semiring -julia> Txy,(x,y) = T["x","y"] -(Multivariate polynomial ring in 2 variables over tropical semiring (min), AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}[x, y]) +julia> R,(x,y) = T["x","y"]; julia> f = x+y+1 x + y + (1) -julia> Tf = TropicalHypersurface(f) -min tropical hypersurface embedded in 2-dimensional Euclidean space +julia> tropical_hypersurface(f) +Min tropical hypersurface + ``` """ -function TropicalHypersurface(f::AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{T}}) where T - if total_degree(f) <= 0 - error("Tropical hypersurfaces of constant polynomials not supported.") - end - M = convention(base_ring(f)) +function tropical_hypersurface(f::MPolyRingElem{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) + @req total_degree(f)>0 "polynomial needs to be non-constant" + + # Construct hypersurface in polymake + minOrMax = convention(f) coeffs, exps = homogenize_and_convert_to_pm(f) - pmhypproj = Polymake.tropical.Hypersurface{M}(MONOMIALS=exps, COEFFICIENTS=coeffs) + pmhypproj = Polymake.tropical.Hypersurface{minOrMax}(MONOMIALS=exps, COEFFICIENTS=coeffs) pmhyp = Polymake.tropical.affine_chart(pmhypproj) - Vf = TropicalHypersurface{M, true}(polyhedral_complex(pmhyp)) - w = pmhypproj.WEIGHTS - set_attribute!(Vf,:polymake_bigobject,pmhypproj) - set_attribute!(Vf,:tropical_polynomial,f) - set_attribute!(Vf,:weights,w) - return Vf -end - -# @doc raw""" -# tropical_variety(f::Union{AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}, -# AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(max)}}}) - -# Return the tropical variety defined by a tropical polynomial in form of a TropicalHypersurface - -# # Examples -# ```jldoctest -# julia> T = TropicalSemiring(min) -# Tropical ring (min) -# julia> Txy,(x,y) = T["x","y"] -# (Multivariate Polynomial Ring in x, y over Tropical ring (min), AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}[x, y]) + # Convert to Oscar objects + polyhedralComplex = polyhedral_complex(pmhyp) + multiplicities = Vector{ZZRingElem}(pmhypproj.WEIGHTS) -# julia> f = x+y+1 -# x + y + (1) + TropH = tropical_hypersurface(polyhedralComplex,multiplicities,minOrMax) + if !weighted_polyhedral_complex_only + set_attribute!(TropH,:polymake_bigobject,pmhypproj) + set_attribute!(TropH,:tropical_polynomial,f) + end + return TropH +end -# julia> Tf = TropicalHypersurface(f) -# A min tropical hypersurface embedded in 2-dimensional Euclidean space -# ``` -# """ -# function tropical_variety(f::Union{AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}, -# AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(max)}}}) -# return TropicalHypersurface(f) -# end @doc raw""" - TropicalHypersurface(f::MPolyRingElem,M::Union{typeof(min),typeof(max)}=min) + tropical_hypersurface(f::MPolyRingElem, val::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) -Given a polynomial `f` over a field with an intrinsic valuation (i.e., a field -on which a function `valuation` is defined such as `PadicField(7,2)`), -return the tropical hypersurface of `f` under the convention specified by `M`. +Return the tropical hypersurface of the tropical polynomial that is the image of `f` under coefficient-wise `val`. If `weighted_polyhedral_complex==true`, will not cache any extra information. # Examples ```jldoctest -julia> K = PadicField(7, 2); +julia> R,(x,y) = QQ["x","y"]; -julia> Kxy, (x,y) = K["x", "y"] -(Multivariate polynomial ring in 2 variables over QQ_7, AbstractAlgebra.Generic.MPoly{padic}[x, y]) +julia> val = tropical_semiring_map(QQ,2) +Map into Min tropical semiring encoding the 2-adic valuation on Rational field -julia> f = 7*x+y+49; +julia> f = x+y+2 +x + y + 2 -julia> TropicalHypersurface(f, min) -min tropical hypersurface embedded in 2-dimensional Euclidean space +julia> tropical_hypersurface(f,val) +Min tropical hypersurface -julia> TropicalHypersurface(f, max) -max tropical hypersurface embedded in 2-dimensional Euclidean space ``` """ -function TropicalHypersurface(f::MPolyRingElem,M::Union{typeof(min),typeof(max)}=min) - tropf = tropical_polynomial(f,M) - Tf = TropicalHypersurface(tropf) - w = pm_object(Tf).WEIGHTS - set_attribute!(Tf,:algebraic_polynomial,f) - set_attribute!(Tf,:tropical_polynomial,tropf) - set_attribute!(Tf,:weights,w) - return Tf +function tropical_hypersurface(f::MPolyRingElem, nu::Union{Nothing,TropicalSemiringMap}=nothing; + weighted_polyhedral_complex_only::Bool=false) + # initialise nu as the trivial valuation if not specified by user + isnothing(nu) && (nu=tropical_semiring_map(coefficient_ring(f))) + + tropf = tropical_polynomial(f,nu) + TropH = tropical_hypersurface(tropf,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + + if !weighted_polyhedral_complex_only + set_attribute!(TropH,:algebraic_polynomial,f) + set_attribute!(TropH,:tropical_semiring_map,nu) + end + return TropH end + @doc raw""" - TropicalHypersurface(f::MPolyRingElem,M::Union{typeof(min),typeof(max)}=min) + tropical_hypersurface(Delta::SubdivisionOfPoints, minOrMax::Union{typeof(min),typeof(max)}=min; weighted_polyhedral_complex_only::Bool=false) -Construct the tropical hypersurface from a polynomial `f` and a map to the -tropical semiring `val`. +Construct the tropical hypersurface dual to a regular subdivision `Delta` in convention `minOrMax` using the minimal weights that give rise to it. If `weighted_polyhedral_complex==true`, will not cache any extra information. + +!!! warning + There is a known bug when the subdivision is too easy, e.g., see example below. # Examples ```jldoctest -julia> Kx, (x1,x2) = polynomial_ring(QQ,2) -(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x1, x2]) - -julia> val = TropicalSemiringMap(QQ,7) -The 7-adic valuation on Rational field +julia> Delta = subdivision_of_points(simplex(2),[0,0,1]) +Subdivision of points in ambient dimension 2 -julia> f = 7*x1+x2+49; - -julia> TropicalHypersurface(f, val) -min tropical hypersurface embedded in 2-dimensional Euclidean space +julia> # tropical_hypersurface(Delta) # issue 2628 ``` """ -function TropicalHypersurface(f::MPolyRingElem, val::TropicalSemiringMap) - tropf = tropical_polynomial(f,val) - Tf = TropicalHypersurface(tropf) - w = pm_object(Tf).WEIGHTS - set_attribute!(Tf,:algebraic_polynomial,f) - set_attribute!(Tf,:tropical_polynomial,tropf) - set_attribute!(Tf,:weights,w) - return Tf -end - - -# @doc raw""" -# tropical_variety(f::MPolyRingElem, M::Union{typeof(min),typeof(max)}) +function tropical_hypersurface(Delta::SubdivisionOfPoints, minOrMax::Union{typeof(min),typeof(max)}=min; + weighted_polyhedral_complex_only::Bool=false) -# Return the tropical variety of an algebraic polynomial in the form of a TropicalHypersurface. -# If M=min, the tropical hypersurface will obey the min-convention. -# If M=max, the tropical hypersurface will obey the max-convention. -# If coefficient ring has a valuation, the tropical hypersurface will be constructed with respect to it. -# If coefficient ring has no valuation, the tropical hypersurface will be constructed with respect to the trivial valuation. -# The function is the same as TropicalHypersurface{M}(f). - -# # Examples -# julia> K = PadicField(7, 2) + PMinOrMax = (minOrMax==typeof(min)) ? Polymake.Min : Polymake.Max + coeffs = Polymake.TropicalNumber{PMinOrMax}.(Polymake.new_integer_from_fmpz.(min_weights(Delta))) + exps = ZZ.(matrix(QQ,points(Delta))) + pmhypproj = Polymake.tropical.Hypersurface{minOrMax}(MONOMIALS=exps, COEFFICIENTS=coeffs) + pmhyp = Polymake.tropical.affine_chart(pmhypproj) -# julia> Kxy, (x,y) = K["x", "y"] + # Convert to Oscar objects + polyhedralComplex = polyhedral_complex(pmhyp) + multiplicities = Vector{ZZRingElem}(pmhypproj.WEIGHTS) -# julia> f = 7*x+y+49 + TropH = tropical_hypersurface(polyhedralComplex,multiplicities,minOrMax) + if !weighted_polyhedral_complex_only + set_attribute!(TropH,:polymake_object,pmhypproj) + set_attribute!(TropH,:subdivision_of_points,Delta) + set_attribute!(TropH,:convention,minOrMax) + end + return TropH +end -# julia> tropical_variety(f,min) -# julia> tropical_variety(f,max) -# """ -# function tropical_variety(f::MPolyRingElem, M::Union{typeof(min),typeof(max)}) -# return TropicalHypersurface{M}(f) -# end ################################################################################ # -# Basic properties for tropical hypersurfaces +# Properties # ################################################################################ - -# todo: add examples for varieties, curves and linear spaces @doc raw""" - dual_subdivision(TH::TropicalHypersurface{M, EMB}) - -Return the dual subdivision of `TH` if it is embedded. Otherwise an error is thrown. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is always of dimension n-1. -```jldoctest -julia> T = TropicalSemiring(min); - -julia> Txy,(x,y) = T["x","y"]; - -julia> f = x+y+1; + algebraic_polynomial(TropH::TropicalHypersurface) -julia> tropicalLine = TropicalHypersurface(f); - -julia> dual_subdivision(tropicalLine) -Subdivision of points in ambient dimension 3 -``` +Return the polynomial over a valued field used to construct `TropH`. Raises an error, if it is not cached. """ -function dual_subdivision(TH::TropicalHypersurface{M,EMB}) where {M,EMB} - if !EMB - error("tropical hypersurface not embedded") - end - - return subdivision_of_points(pm_object(TH).DUAL_SUBDIVISION) +function algebraic_polynomial(TropH::TropicalHypersurface) + @req has_attribute(TropH,:algebraic_polynomial) "no algebraic polynomial cached" + return get_attribute(TropH,:algebraic_polynomial) end -@doc raw""" - polynomial(TH::TropicalHypersurface{M, EMB}) - -Return the tropical polynomial of `TH` if it is embedded. Otherwise an error is thrown. - -# Examples -```jldoctest -julia> T = TropicalSemiring(min); +# @doc raw""" +# convention(TropH::TropicalHypersurface) -julia> Txy,(x,y) = T["x","y"]; +# Return min or max depending on the convention of `TropH`. Raises an error, if neither it nor a tropical semiring map is cached. +# """ +# function convention(TropH::TropicalHypersurface) +# if has_attribute(TropH,:convention) +# return get_attribute(TropH,:convention) +# elseif has_attribute(TropH,:tropical_semiring_map) +# return convention(get_attribute(TropH,:tropical_semiring_map)) +# end +# error("neither convention nor tropical semiring map cached") +# end -julia> f = x+y+1; -julia> TH = TropicalHypersurface(f); +@doc raw""" + dual_subdivision(TropH::TropicalHypersurface) -julia> polynomial(TH) -x + y + (1) -``` +Return the dual subdivision of `TropH`. Raises an error, if neither it nor the the internal polymake object is cached. """ -function polynomial(TH::TropicalHypersurface{M,EMB}) where {M,EMB} - if !EMB - error("tropical hypersurface not embedded") +function dual_subdivision(TropH::TropicalHypersurface{minOrMax,true}) where minOrMax + if has_attribute(TropH,:dual_subdivision) + return get_attribute(TropH,:dual_subdivision) + elseif has_attribute(TropH,:polymake_bigobject) + return get_attribute(TropH,:polymake_bigobject) end - return get_attribute(TH,:tropical_polynomial) + error("neither dual subdivision nor polymake object cached") end @doc raw""" - minpoly(T::TropicalHypersurface) + tropical_polynomial(TropH::TropicalHypersurface) -Return the minimal polynomial with smallest possible coefficients of a hypersurface. +Return the tropical polynomial used to construct `TropH`. Raises an error, if it is not cached. """ -function minpoly(T::TropicalHypersurface) - error("function not implemented yet") - return +function tropical_polynomial(TropH::TropicalHypersurface) + @req has_attribute(TropH,:tropical_polynomial) "no tropical polynomial cached" + return get_attribute(TropH,:tropical_polynomial) end + + +# @doc raw""" +# tropical_semiring_map(TropH::TropicalHypersurface) + +# Return the tropical semiring map used to construct `TropH`. Raises an error, if it is not cached. +# """ +# function tropical_semiring_map(TropH::TropicalHypersurface) +# @req has_attribute(TropH,:tropical_semiring_map) "no tropical semiring map cached" +# return get_attribute(TropH,:tropical_semiring_map) +# end diff --git a/src/TropicalGeometry/initial.jl b/src/TropicalGeometry/initial.jl index 7a3a0a15dee7..b30964cb0469 100644 --- a/src/TropicalGeometry/initial.jl +++ b/src/TropicalGeometry/initial.jl @@ -1,208 +1,113 @@ -### -# Computing initial forms and initial ideals in Oscar -# =================================================== -### +################################################################################ +# +# Initial forms and initial ideals +# +################################################################################ @doc raw""" - valued_weighted_degree(f::MPolyRingElem, val::TropicalSemiringMap, w::Vector; perturbation::Vector=[], return_vector::Bool=false) + initial(f::MPolyRingElem, nu::TropicalSemiringMap, w::Vector; perturbation::Vector=[]) -Return the valued weighted degree of a polynomial `f` with respect to valuation -`val` and weight vector `w`. In other words, returns the tropicalized -polynomial of `f` with respect to valuation `val` evaluated at `w`. +Return the initial form of `f` with respect to the tropical semiring map `nu` and weight vector `w`. -If `return_vector=true`, returns a vector whose i-th entry is the valued -weighted degree of the i-th term of `f`. - -# Examples +# Examples (trivial and $p$-adic valuation) ```jldoctest -julia> Kxy, (x,y) = polynomial_ring(QQ,["x", "y"]); - -julia> val_2 = TropicalSemiringMap(QQ,2); +julia> R,(x,y) = QQ["x", "y"]; -julia> val_trivial = TropicalSemiringMap(QQ); +julia> nu_0 = tropical_semiring_map(QQ,max); -julia> w = [1,1]; +julia> nu_2 = tropical_semiring_map(QQ,2); -julia> f = 2*x+2*y+1; +julia> w = [0,0]; -julia> valued_weighted_degree(f, val_2, w) -(0) +julia> f = x+y+2; -julia> valued_weighted_degree(f, val_2, w, return_vector=true) -((0), Oscar.TropicalSemiringElem{typeof(min)}[(2), (2), (0)]) +julia> initial(f,nu_2,w) # polynomial over GF(2) +x + y -julia> valued_weighted_degree(f, val_trivial, w, return_vector=true) -((0), Oscar.TropicalSemiringElem{typeof(min)}[(1), (1), (0)]) +julia> initial(f,nu_0,w) # polynomial over QQ +x + y + 2 ``` -""" -function valued_weighted_degree(f::MPolyRingElem, val::TropicalSemiringMap, w::Vector; perturbation::Vector=[], return_vector::Bool=false) - # compute the weighted degrees shifted by the coefficient valuations - vwds = [val(c)*TropicalSemiring(val)(dot(w,alpha)) for (c,alpha) in zip(AbstractAlgebra.coefficients(f),AbstractAlgebra.exponent_vectors(f))] - - # compute the minimal degree - # (note: max tropical semiring is reversely ordered, so min in the semiring is max in the conventional sense) - vwd = min(vwds...) - - if isempty(perturbation) - # if no perturbation is specified, compute the maximum and return vector if required - if return_vector - return vwd,vwds - end - return vwd - else - # if perturbation is specified, then compute the pertubed degrees - vwdsPerp = [TropicalSemiring(val)(dot(perturbation,alpha)) for alpha in AbstractAlgebra.exponent_vectors(f)] - # compute the minimum amongst all perturbations with maximal original degree - vwdPerp = min([vwdsPerp[i] for i in 1:length(vwds) if vwds[i]==vwd]...) - - if return_vector - return vwd,vwdPerp,vwds,vwdsPerp - end - return vwd,vwdPerp - end - -end - - - -# # not wrong, but not sure whether needed -# function weighted_degree(f::AbstractAlgebra.Generic.MPoly{<:RingElement}, w::Vector; return_vector::Bool=false) -# trivial_val = TropicalSemiringMap(coefficient_ring(f)) -# return valued_weighted_degree(f, trivial_val, w, return_vector=return_vector) -# end - - -@doc raw""" - initial(f::MPolyRingElem, val::TropicalSemiringMap, w::Vector, convention::Union{typeof(min),typeof(max)}=min; perturbation::Vector=[]) - -Return the initial form of `f` with respect to valuation `val` and weight `w`. -If convention==min (default), it is computed in the min convention. If -convention==max, it is computed in the max convention. - -For the definition of initial form in the min-convention, see -Section 2.4 of [MS15](@cite). - -# Examples +# Examples ($t$-adic valuation) ```jldoctest -julia> Kxy, (x,y) = polynomial_ring(QQ,["x", "y"]); - -julia> w = [1,1]; - -julia> val_2 = TropicalSemiringMap(QQ,2); - -julia> val_trivial = TropicalSemiringMap(QQ); +julia> K,t = rational_function_field(GF(2),"t"); -julia> f = 2*x+2*y+1; +julia> nu_t = tropical_semiring_map(K,t,max); -julia> initial(f,val_2,w) # polynomial over GF(2) -1 - -julia> initial(f,val_trivial,w) -1 -``` -```jldoctest -julia> Kt,t = rational_function_field(QQ,"t"); +julia> R,(x,y) = K["x", "y"]; julia> w = [1,1]; -julia> Ktxy, (x,y) = polynomial_ring(Kt,["x", "y"]); - julia> f = t*x+t*y+1; -julia> val_t = TropicalSemiringMap(Kt,t); +julia> initial(f,nu_t,w) # polynomial over GF(2) +x + y + 1 -julia> initial(f,val_t,w) # polynomial over QQ -1 ``` -```jldoctest -julia> Kt,t = rational_function_field(GF(32003),"t"); +""" +function initial(f::MPolyRingElem, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}; perturbation::Union{Nothing,Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}}=nothing) + + ### + # Evaluate the tropicalization of f and all its terms at w, + # mark the terms which attain the evaluated value + ### + coeffs = collect(coefficients(f)) + expvs = collect(exponents(f)) + tropTermsEvaluated = [nu(c)*dot(w,alpha) for (c,alpha) in zip(coeffs,expvs)] + tropPolyEvaluated = sum(tropTermsEvaluated) + termsAttainingValue = findall(isequal(tropPolyEvaluated),tropTermsEvaluated) + coeffs = coeffs[termsAttainingValue] + expvs = expvs[termsAttainingValue] + + # if perturbation passed, further filter the marked terms + if !isnothing(perturbation) + tropTermsEvaluated = [tropical_semiring(nu)(dot(w,alpha)) for (c,alpha) in zip(coeffs,expvs)] + tropPolyEvaluated = sum(tropTermsEvaluated) + termsAttainingValue = findall(isequal(tropPolyEvaluated),tropTermsEvaluated) + coeffs = coeffs[termsAttainingValue] + expvs = expvs[termsAttainingValue] + end -julia> Ktxy, (x,y) = polynomial_ring(Kt,["x", "y"]); + ### + # Construct the initial form + ### + kx,_ = polynomial_ring(residue_field(nu),symbols(parent(f))) + initialForm = MPolyBuildCtx(kx) + for (c,alpha) in zip(coeffs,expvs) + push_term!(initialForm,initial(c,nu),alpha) + end + return finish(initialForm) +end -julia> w = [1,1]; -julia> f = t*x+t*y+1; -julia> val_t = TropicalSemiringMap(Kt,t); +@doc raw""" + initial(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector; skip_groebner_basis_computation::Bool=false) -julia> initial(f,val_t,w) # polynomial over QQ -1 -``` -""" -function initial(f::MPolyRingElem, val::TropicalSemiringMap, w::Vector; perturbation::Vector=[]) - # compute the maximal weighted degrees - # todo (optional): - # currently, we iterate over the entire polynomial to compute the (terms with) maximal valuated weighted degrees - # often this is not necessary as the polynomial is already sorted w.r.t. it - if isempty(perturbation) - vwd,vwds = valued_weighted_degree(f, val, w, return_vector=true) - else - vwd,vwdPerp,vwds,vwdsPerp = valued_weighted_degree(f, val, w, perturbation=perturbation, return_vector=true) - end - - # initial(f) is the sum over all pi(c_alpha*t^-val(c_alpha))x^alpha - # where c_alpha x^alpha is a term of maximal valued weighted degree - # and pi is the map from the valued field to the residue field - if is_valuation_trivial(val) - t = val.valued_field(1) - else - t = val.valued_field(val.uniformizer_field) - end - kx, x = polynomial_ring(val.residue_field,[repr(x) for x in gens(parent(f))]) - R = val.valued_ring - pi = val.residue_map - - initialf = MPolyBuildCtx(kx) - if isempty(perturbation) - for (vwdi,cf,expv) in zip(vwds,AbstractAlgebra.coefficients(f),AbstractAlgebra.exponent_vectors(f)) - if vwdi == vwd - vcf = Int(val(cf),preserve_ordering=true) - c = t^-vcf*cf # make coefficient valuation 0 - cNum = numerator(c) # split up numerator and denominator as pi is only defined on the valued ring - cDen = denominator(c) - push_term!(initialf, pi(cNum)//pi(cDen), expv) # apply pi to both and divide the result - end - end - else - for (vwdi,vwdiPerp,cf,expv) in zip(vwds,vwdsPerp,AbstractAlgebra.coefficients(f),AbstractAlgebra.exponent_vectors(f)) - if vwdi == vwd && vwdiPerp == vwdPerp - vcf = Int(val(cf),preserve_ordering=true) - c = t^-vcf*cf - cNum = numerator(c) - cDen = denominator(c) - push_term!(initialf, pi(cNum)//pi(cDen), expv) - end - end - end +Return the initial ideal of `I` with respect to the tropical semiring map `nu` and weight vector `w`. If `skip_groebner_basis_computation=true`, skips the necessary Groebner basis computation and returns the ideal generated by the initial forms of `gens(I)`. - return finish(initialf) -end -function initial(G::Vector, val::TropicalSemiringMap, w::Vector; perturbation::Vector=[]) - return [initial(g,val,w,perturbation=perturbation) for g in G] -end +# Examples +```jldoctest +julia> R,(x,y) = QQ["x","y"]; +julia> I = ideal([x^3-5*x^2*y,3*y^3-2*x^2*y]); +julia> nu_2 = tropical_semiring_map(QQ,2); +julia> nu_0 = tropical_semiring_map(QQ); -@doc raw""" - initial(I::MPolyIdeal, val::TropicalSemiringMap, w::Vector; skip_groebner_basis_computation::Bool=false, skip_legality_check::Bool=false) +julia> w = [0,0]; -Return the initial ideal of `I` with respect to valuation `val` and weight `w`. -For the definition of initial ideal, see Section 2.4 of [MS15](@cite). +julia> initial(I,nu_2,w) +ideal(x^3 + x^2*y, y^3) -Use at your own risk: If `skip_groebner_basis_computation=true`, skips Groebner -basis computation. If `skip_legality_check=true`, skips check whether valuation -and weight vector are legal, i.e., if `I` is non-homogeneous, then `val` may -only be trivial and `w` may only have non-negative entries. +julia> initial(I,nu_0,w) +ideal(2*x^2*y - 3*y^3, x^3 - 5*x^2*y, x*y^3 - 5*y^4, y^5) +``` """ -function initial(I::MPolyIdeal, val::TropicalSemiringMap, w::Vector; skip_groebner_basis_computation::Bool=false) - if !skip_groebner_basis_computation - G = groebner_basis(I,val,w) - else - G = gens(G) - end - return ideal(initial(G,val,w)) +function initial(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector{<:Union{QQFieldElem,ZZRingElem,Rational,Integer}}; skip_groebner_basis_computation::Bool=false) + G = (skip_groebner_basis_computation ? gens(G) : groebner_basis(I,nu,w)) + return ideal(initial.(G,Ref(nu),Ref(w))) end diff --git a/src/TropicalGeometry/intersection.jl b/src/TropicalGeometry/intersection.jl new file mode 100644 index 000000000000..eedcd1ab5e83 --- /dev/null +++ b/src/TropicalGeometry/intersection.jl @@ -0,0 +1,127 @@ +################################################################################ +# +# Stable intersections +# +################################################################################ + +@doc raw""" + stable_intersection(TropV1::TropicalVariety, TropV2::TropicalVariety) + +Return the stable intersection of `TropV1` and `TropV2`. +""" +function stable_intersection(TropV1::TropicalVarietySupertype{minOrMax,true}, TropV2::TropicalVarietySupertype{minOrMax,true}, + perturbation::Union{Vector{Int},Nothing}=nothing) where minOrMax + + @req ambient_dim(TropV1)==ambient_dim(TropV2) "different ambient dimenions of tropical varieties" + if isnothing(perturbation) + perturbation = rand(Int,ambient_dim(TropV1)) + end + + n = ambient_dim(TropV1) + Sigma12 = Polyhedron[] + mults12 = ZZRingElem[] + + # todo: check that perturbation is actually generic + for (sigma1,m1) in maximal_polyhedra_and_multiplicities(TropV1) + for (sigma2,m2) in maximal_polyhedra_and_multiplicities(TropV2) + if dim(sigma1+sigma2)==n && intersect_after_perturbation(sigma1,sigma2,perturbation) + sigma12 = intersect(sigma1, sigma2) + i = findfirst(isequal(sigma12), Sigma12) + if isnothing(i) + push!(Sigma12, intersect(sigma1, sigma2)) + push!(mults12, m1*m2*tropical_intersection_multiplicity(sigma1,sigma2)) + else + mults12[i] += m1*m2*tropical_intersection_multiplicity(sigma1,sigma2) + end + end + end + end + + return tropical_variety(Sigma12,mults12,minOrMax) +end + +function intersect_after_perturbation(sigma1::Polyhedron{QQFieldElem}, sigma2::Polyhedron{QQFieldElem}, perturbation::Vector{Int}) + + if dim(intersect(sigma1,sigma2))<0 + return false + end + + # construct sigma1Prime = sigma1 x RR in RR^(n+1) + M = affine_inequality_matrix(facets(sigma1)) + M = hcat(M, zero_matrix(QQ, nrows(M), 1)) + N = affine_equation_matrix(affine_hull(sigma1)) + N = hcat(N, zero_matrix(QQ, nrows(N), 1)) + sigma1Prime = polyhedron((M[:,2:end],[-M[:,1]...]), (N[:,2:end],[-N[:,1]...])) + + # construct sigma2Prime = (sigma2 x {0}) + RR_{>=0} * (perturbation,1) + M = affine_inequality_matrix(facets(sigma2)) + M = hcat(M, zero_matrix(QQ, nrows(M), 1)) + N = affine_equation_matrix(affine_hull(sigma2)) + N = hcat(N, zero_matrix(QQ, nrows(N), 1)) + v = zero_matrix(QQ, 1, ncols(N)) + v[1,end] = 1 # v = last unit vector + N = vcat(N, v) + sigma2Prime = polyhedron((M[:,2:end],[-M[:,1]...]), (N[:,2:end],[-N[:,1]...])) + convex_hull(zero_matrix(QQ, 1, ncols(N) - 1), matrix(QQ, [vcat(perturbation, [1])])) + + sigma12Prime = intersect(sigma1Prime, sigma2Prime) + # @req codim(sigma1Prime)+codim(sigma2Prime)==codim(sigma12Prime) "perturbation "*string(perturbation)*" not generic" + + return dim(sigma12Prime)>0 && last(relative_interior_point(sigma12Prime))>0 +end + + +# Input: B1, B2 matrices whose rows are generating sets of two euclidean linear spaces, +# whose sum is the entire space +# Output: the tropical intersection number as defined in [Maclagan-Sturmfels, Definition 3.6.5] +# todo: rewrite function below so that it takes polyhedra as input +function tropical_intersection_multiplicity(sigma1::Polyhedron,sigma2::Polyhedron) + B1 = kernel_basis(affine_equation_matrix(affine_hull(sigma1))[:,2:end]) + B1 = matrix(ZZ,[ numerator.(b .* lcm(denominator.(b))) for b in B1 ]) + B1 = saturate(B1) + + B2 = kernel_basis(affine_equation_matrix(affine_hull(sigma2))[:,2:end]) + B2 = matrix(ZZ,[ numerator.(b .* lcm(denominator.(b))) for b in B2 ]) + B2 = saturate(B2) + + @req ncols(B1) == ncols(B2) && nrows(B1)+nrows(B2) >= ncols(B1) "polyhedra do not span ambient space" + + snfB12 = snf(vcat(B1,B2)) + return abs(prod([snfB12[i,i] for i in 1:ncols(snfB12)])) +end + + + +################################################################################ +# +# Stable intersections of tropical linear spaces +# +# Todo: make this use algebraic_pluecker_vector if available +# Problem: the +/- in the formula of speyers paper +# +################################################################################ + +function stable_intersection(TropL1::TropicalLinearSpace{minOrMax,true}, TropL2::TropicalLinearSpace{minOrMax,true}) where minOrMax + + plueckerIndices12 = Vector{Int}[] + plueckerVector12 = TropicalSemiringElem{typeof(minOrMax)}[] + d = codim(TropL1)+codim(TropL2) + + for (I1,p1) in zip(pluecker_indices(TropL1),tropical_pluecker_vector(TropL1)) + for (I2,p2) in zip(pluecker_indices(TropL2),tropical_pluecker_vector(TropL2)) + I12 = intersect(I1,I2) + if length(I12)>d + continue + end + + i = searchsortedfirst(plueckerIndices12,I12) + if i<=length(plueckerIndices12) && plueckerIndices12[i]==I12 + plueckerVector12[i] += p1*p2 + else + insert!(plueckerIndices12,i,I12) + insert!(plueckerVector12,i,p1*p2) + end + end + end + + return tropical_linear_space(plueckerIndices12,plueckerVector12) +end diff --git a/src/TropicalGeometry/linear_space.jl b/src/TropicalGeometry/linear_space.jl index 9b82ff347dc8..1f57825ae694 100644 --- a/src/TropicalGeometry/linear_space.jl +++ b/src/TropicalGeometry/linear_space.jl @@ -1,140 +1,401 @@ -### -# Tropical linear spaces in Oscar -# =============================== -### - - -### -# 1. Definition -# ------------- -# M = typeof(min) or typeof(max): -# min or max convention, affecting initial ideals, Pluecker vector, etc. -# EMB = true or false: -# embedded or abstract tropical linear space -# embedded tropical linear space = weighted polyhedral complex in euclidean space -# abstract tropical linear space = weighted hypergraph with enumerated vertices -### - -@attributes mutable struct TropicalLinearSpace{M,T} <: TropicalVarietySupertype{M,T} - # GapTV::GapObj +############################################################################### +# +# Tropical linear spaces +# ====================== +# concrete subtype of TropicalVarietySupertype in variety_supertype.jl +# +############################################################################### + +@attributes mutable struct TropicalLinearSpace{minOrMax,isEmbedded} <: TropicalVarietySupertype{minOrMax,isEmbedded} polyhedralComplex::PolyhedralComplex - function TropicalLinearSpace{M,T}(Sigma::PolyhedralComplex) where {M,T} - return new{M,T}(Sigma) + multiplicities::Vector{ZZRingElem} + + # tropical linear spaces need to be embedded + function TropicalLinearSpace{minOrMax,true}(Sigma::PolyhedralComplex, multiplicities::Vector{ZZRingElem}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return new{minOrMax,true}(Sigma,multiplicities) end end -### -# 2. Basic constructors -# --------------------- -### +############################################################################### +# +# Printing +# +############################################################################### + +function Base.show(io::IO, th::TropicalLinearSpace{typeof(min), true}) + print(io, "Min tropical linear space") +end +function Base.show(io::IO, th::TropicalLinearSpace{typeof(max), true}) + print(io, "Max tropical linear space") +end + + + +############################################################################### +# +# Constructors +# +############################################################################### + +function tropical_linear_space(Sigma::PolyhedralComplex, mult::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalLinearSpace{typeof(minOrMax),true}(Sigma,mult) +end + + +function tropical_linear_space(TropV::TropicalVarietySupertype{minOrMax,true}) where {minOrMax<:Union{typeof(min),typeof(max)}} + mult = multiplicities(TropV) + @req isnothing(findfirst(!isequal(one(ZZ)),collect(values(mult)))) "tropical variety not all multiplicities one" + return tropical_linear_space(polyhedral_complex(TropV),mult,convention(TropV)) +end + + +function shift_pluecker_indices_for_polymake(plueckerIndices::Vector{Vector{Int}}) + # substract 1 fromt all entries of plueckerIndices + return (x -> x .-1).(plueckerIndices) +end + + +function add_missing_lineality_from_polymake(Sigma::PolyhedralComplex) + # Adding missing ones vector to lineality space + IM = maximal_polyhedra(IncidenceMatrix,Sigma) + VR = vertices_and_rays(Sigma) + rayIndices = findall(vr->(vr isa RayVector),VR) + VRmat = matrix(QQ,Vector{QQFieldElem}.(collect(VR))) + L = vcat(matrix(QQ,lineality_space(Sigma)), + matrix(QQ,ones(Int,1,ambient_dim(Sigma)))) + return polyhedral_complex(IM,VRmat,rayIndices,L) +end + + +@doc raw""" + tropical_linear_space(Lambda::Vector{Vector{Int}}, p::Vector{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) + +Return a tropical linear space from a tropical Pluecker vector with indices `Lambda` and values `p`. If `weighted_polyhedral_complex==true`, will not cache any extra information. + +# Examples +```jldoctest +julia> T = tropical_semiring(); + +julia> plueckerIndices = [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]; + +julia> plueckerVector = T.([0,0,0,0,0,0]); + +julia> tropical_linear_space(plueckerIndices,plueckerVector) +Min tropical linear space + +``` +""" +function tropical_linear_space(plueckerIndices::Vector{Vector{Int}}, plueckerVector::Vector{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) + + # read off convention and indices of finite entries + minOrMax = convention(plueckerVector) + plueckerSupport = findall(!iszero,plueckerVector) + + # restrict plueckerVector and pluckerIndices, + # convert plueckerVector to QQ (for Polymake) + plueckerVectorForPolymake = QQ.(plueckerVector[plueckerSupport]) + plueckerIndicesForPolymake = shift_pluecker_indices_for_polymake(plueckerIndices[plueckerSupport]) + + # find out ambient dimension from remaining indices + n = length(unique(Iterators.flatten(plueckerIndices))) + + # construct tropical linear space + valuatedMatroid = Polymake.matroid.ValuatedMatroid{minOrMax}( + BASES = plueckerIndicesForPolymake, + N_ELEMENTS = n, + VALUATION_ON_BASES = plueckerVectorForPolymake) + + Sigma = PolyhedralComplex{QQFieldElem}(Polymake.tropical.linear_space{minOrMax}(valuatedMatroid)) + Sigma = add_missing_lineality_from_polymake(Sigma) + multiplicities = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) + + TropL = tropical_linear_space(Sigma,multiplicities,minOrMax) + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:polymake_object,valuatedMatroid) + set_attribute!(TropL,:pluecker_indices,plueckerIndices) + set_attribute!(TropL,:tropical_pluecker_vector,plueckerVector) + set_attribute!(TropL,:valuated_matroid,valuatedMatroid) + end + return TropL +end + @doc raw""" - TropicalLinearSpace(I::MPolyIdeal, val::TropicalSemiringMap) + tropical_linear_space(k::Int, n::Int, p::Vector{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) -Construct a tropical linear space from a degree 1 polynomial ideal `I` and a map to the tropical semiring `val`. +Return a tropical linear space from a tropical Pluecker vector with indices `AbstractAlgebra.combinations(1:n,k)` and values `p`. If `weighted_polyhedral_complex==true`, will not cache any extra information. # Examples +```jldoctest +julia> T = tropical_semiring(); + +julia> plueckerVector = T.([0,0,0,0,0,0]); + +julia> tropical_linear_space(2,4,plueckerVector) +Min tropical linear space + +``` +""" +function tropical_linear_space(k::Int, n::Int, plueckerVector::Vector{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) + return tropical_linear_space(AbstractAlgebra.combinations(1:n,k), plueckerVector, weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) +end + + +@doc raw""" + tropical_linear_space(Lambda::Vector{Vector{Int}}, p::Vector, nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) + +Return a tropical linear space from a tropical Pluecker vector with indices `Lambda` and values `nu(p)`. If `weighted_polyhedral_complex==true`, will not cache any extra information. +# Examples ```jldoctest -julia> R,(x1,x2,x3,x4,x5,x6) = polynomial_ring(ZZ,6) -(Multivariate polynomial ring in 6 variables over ZZ, ZZMPolyRingElem[x1, x2, x3, x4, x5, x6]) +julia> nu = tropical_semiring_map(QQ,2) +Map into Min tropical semiring encoding the 2-adic valuation on Rational field + +julia> plueckerIndices = [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]; -julia> I = ideal(R,[-x1+x3+x4,-x2+x3+x5,-x1+x2+x6]) -ideal(-x1 + x3 + x4, -x2 + x3 + x5, -x1 + x2 + x6) +julia> plueckerVector = QQ.([1,3,5,5,3,1]); -julia> val = TropicalSemiringMap(ZZ) -The trivial valuation on Integer ring +julia> tropical_linear_space(plueckerIndices,plueckerVector,nu) +Min tropical linear space -julia> TropicalLinearSpace(I,val) -TropicalLinearSpace{min, true}(Polyhedral complex in ambient dimension 6, #undef) ``` """ -function TropicalLinearSpace(I::MPolyIdeal, val) - R = base_ring(I) - n = ngens(R) - g = gens(I) - l = length(g) - id = [ v for v in identity_matrix(ZZ,n)] - A = [ [ coeff(p,Vector{Int}(v)) for v in [id[i,:] for i in 1:nrows(id)] ] for p in gens(I) ] - B = kernel_basis(matrix(QQ,A)) - return TropicalLinearSpace(matrix(B),val) +function tropical_linear_space(plueckerIndices::Vector{Vector{Int}}, plueckerVector::Vector, nu::Union{Nothing,TropicalSemiringMap}=nothing; weighted_polyhedral_complex_only::Bool=false) + # if nu unspecified, initialise as the trivial valuation + min convention + isnothing(nu) && (nu=tropical_semiring_map(parent(first(plueckerVector)))) + + TropL = tropical_linear_space(plueckerIndices, + nu.(plueckerVector), + weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:algebraic_pluecker_vector,plueckerVector) + set_attribute!(TropL,:tropical_semiring_map,nu) + end + return TropL end + @doc raw""" - TropicalLinearSpace(plv::Vector{TropicalSemiringElem}, rank::IntegerUnion, nElements::IntegerUnion) + tropical_linear_space(k::Int, n::Int, p::Vector, nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) -Construct a tropical linear space from a (tropical) Pluecker vector `plv`, rank `rank`, and size of the ground set `nElements`. +Return a tropical linear space from a tropical Pluecker vector with indices `AbstractAlgebra.combinations(1:n,k)` and values `nu(p)`. If `weighted_polyhedral_complex==true`, will not cache any extra information. -#Examples +# Examples ```jldoctest -julia> R = TropicalSemiring(min); +julia> nu = tropical_semiring_map(QQ); + +julia> plueckerVector = QQ.([1,3,5,5,3,1]); + +julia> tropical_linear_space(2,4,plueckerVector,nu) +Min tropical linear space + +``` +""" +function tropical_linear_space(k::Int, n::Int, plueckerVector::Vector, nu::Union{Nothing,TropicalSemiringMap}=nothing; weighted_polyhedral_complex_only::Bool=false) + # if nu unspecified, initialise as the trivial valuation + min convention + isnothing(nu) && (nu=tropical_semiring_map(parent(first(plueckerVector)))) + + TropL = tropical_linear_space(AbstractAlgebra.combinations(1:n,k), nu.(plueckerVector), weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:algebraic_pluecker_vector,plueckerVector) + set_attribute!(TropL,:tropical_semiring_map,nu) + end + return TropL +end + -julia> plv = [R(e) for e in [2,1,1,0,0,zero(R)]]; +@doc raw""" + tropical_linear_space(A::MatElem{<:TropicalSemiringElem}; weighted_polyhedral_complex_only::Bool=false) + +Return a tropical linear space whose Pluecker vector are the tropical minors of `A`. If `weighted_polyhedral_complex==true`, will not cache any extra information. + +# Examples +```jldoctest +julia> A = matrix(tropical_semiring(),[[1,2,4,8],[8,4,2,1]]) +[(1) (2) (4) (8)] +[(8) (4) (2) (1)] -julia> L = TropicalLinearSpace(plv, 2, 4) -TropicalLinearSpace{min, true}(Polyhedral complex in ambient dimension 4, #undef) +julia> tropical_linear_space(A) +Min tropical linear space -julia> f_vector(L) -2-element Vector{Int64}: - 1 - 3 ``` """ -function TropicalLinearSpace_impl(plv, rank, nElements, M) - Zero = zero(TropicalSemiring(M)) - indexSet = findall(i->i!=Zero, plv) - bases = [ sort(Hecke.subsets(Vector{Int}(0:nElements-1), rank))[i] for i in indexSet ] - val = Polymake.matroid.ValuatedMatroid{M}(BASES = bases, N_ELEMENTS = nElements,VALUATION_ON_BASES = [plv[i].data for i in indexSet]) - #return Polymake.tropical.linear_space{min}(val) - P = Polymake.tropical.linear_space{M}(val) - P = PolyhedralComplex{QQFieldElem}(P, QQ) - return TropicalLinearSpace{M,true}(P) -end -TropicalLinearSpace(plv::Vector{TropicalSemiringElem{typeof(min)}},rank::IntegerUnion, nElements::IntegerUnion) = -TropicalLinearSpace_impl(plv, rank, nElements, min) -TropicalLinearSpace(plv::Vector{TropicalSemiringElem{typeof(max)}},rank::IntegerUnion, nElements::IntegerUnion) = -TropicalLinearSpace_impl(plv, rank, nElements, max) +function tropical_linear_space(A::Union{Matrix{T},MatElem{T}}; weighted_polyhedral_complex_only::Bool=false) where {T<:TropicalSemiringElem} + # convert to Oscar matrix (necessary for AbstractAlgebra.minors) + A isa Matrix && (A = matrix(parent(first(A)),A)) + + n = max(nrows(A), ncols(A)) + k = min(nrows(A), ncols(A)) + plueckerIndices = AbstractAlgebra.combinations(1:n,k) + plueckerVector = AbstractAlgebra.minors(A, k) + TropL = tropical_linear_space(plueckerIndices, plueckerVector, + weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:tropical_matrix,A) + end + return TropL +end @doc raw""" - TropicalLinearSpace(A::MatElem,val::TropicalSemiringMap) + tropical_linear_space(A::MatElem,nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) -Construct a tropical linear space from a matrix `A` and a map to the tropical semiring `val`. +Return a tropical linear space whose Pluecker vector is `nu` applied to the minors of `A`. If `weighted_polyhedral_complex==true`, will not cache any extra information. # Examples ```jldoctest -julia> Kt, t = rational_function_field(QQ,"t"); +julia> nu = tropical_semiring_map(QQ,2) +Map into Min tropical semiring encoding the 2-adic valuation on Rational field + +julia> A = matrix(QQ,[[1,2,4,8],[8,4,2,1]]) +[1 2 4 8] +[8 4 2 1] -julia> val = TropicalSemiringMap(Kt,t); +julia> tropical_linear_space(A, nu) +Min tropical linear space -julia> A = matrix(Kt,[[t,4*t,0,2],[1,4,1,t^2]]); +``` +""" +function tropical_linear_space(A::MatElem, nu::Union{Nothing,TropicalSemiringMap}=nothing; weighted_polyhedral_complex_only::Bool=false) + # if nu unspecified, initialise as the trivial valuation + min convention + isnothing(nu) && (nu=tropical_semiring_map(base_ring(A))) + + n = max(nrows(A), ncols(A)) + k = min(nrows(A), ncols(A)) + plueckerIndices = AbstractAlgebra.combinations(1:n,k) + plueckerVector = AbstractAlgebra.minors(A, k) + TropL = tropical_linear_space(plueckerIndices, plueckerVector, nu, + weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:algebraic_matrix,A) + set_attribute!(TropL,:tropical_semiring_map,nu) + end + return TropL +end -julia> TropicalLinearSpace(A, val) -TropicalLinearSpace{min, true}(Polyhedral complex in ambient dimension 4, #undef) -julia> p = 3; +@doc raw""" + tropical_linear_space(I::MPolyIdeal, nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) + +Return the tropicalization of the vanishing set of `I` with respect to the tropical semiring map `nu`. If `weighted_polyhedral_complex==true`, will not cache any extra information. -julia> val = TropicalSemiringMap(QQ, p); +# Examples -julia> A = matrix(QQ, [[3,7,5,1], [9,7,1,2]]) -[3 7 5 1] -[9 7 1 2] +```jldoctest +julia> R,(x1,x2,x3,x4) = polynomial_ring(QQ,4); + +julia> I = ideal(R,[-x1+x3,-x2+x4]) +ideal(-x1 + x3, -x2 + x4) + +julia> nu = tropical_semiring_map(QQ) +Map into Min tropical semiring encoding the trivial valuation on Rational field + +julia> tropical_linear_space(I, nu) +Min tropical linear space -julia> TropicalLinearSpace(A,val) -TropicalLinearSpace{min, true}(Polyhedral complex in ambient dimension 4, #undef) ``` """ -function TropicalLinearSpace(A::MatElem, val) - plv = [val(p) for p in Nemo.minors(A, min(nrows(A), ncols(A)))] - rk = rank(A) - nelement = max(nrows(A), ncols(A)) - return TropicalLinearSpace(plv, rk, nelement) +function tropical_linear_space(I::MPolyIdeal, nu::Union{Nothing,TropicalSemiringMap}=nothing; weighted_polyhedral_complex_only::Bool=false) + # initialise nu as the trivial valuation if not specified by user + isnothing(nu) && (nu=tropical_semiring_map(coefficient_ring(I))) + + x = gens(base_ring(I)) + G = gens(I) + macaulayMatrix = matrix([[coeff(g,xi) for xi in x] for g in G]) + A = matrix(kernel_basis(macaulayMatrix)) + TropL = tropical_linear_space(A,nu, + weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + if !weighted_polyhedral_complex_only + set_attribute!(TropL,:algebraic_ideal,I) + set_attribute!(TropL,:tropical_semiring_map,nu) + end + return TropL +end + + + +############################################################################### +# +# Properties +# +############################################################################### + +@doc raw""" + pluecker_indices(TropL::TropicalLinearSpace) + +Return the Pluecker indices used to construct `TropL`. Raises an error, if it is not cached. +""" +function pluecker_indices(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:pluecker_indices) "no pluecker indices cached" + return get_attribute(TropL,:pluecker_indices) +end + + +@doc raw""" + tropical_pluecker_vector(TropL::TropicalLinearSpace) + +Return the tropical Pluecker vector of `TropL`. Raises an error, if it is not cached. +""" +function tropical_pluecker_vector(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:tropical_pluecker_vector) "no tropical pluecker vector cached" + return get_attribute(TropL,:tropical_pluecker_vector) +end + + +@doc raw""" + algebraic_pluecker_vector(TropL::TropicalLinearSpace) + +Return the Pluecker vector over a valued field used to construct `TropL`. Raises an error, if it is not cached. +""" +function algebraic_pluecker_vector(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:algebraic_pluecker_vector) "no algebraic pluecker vector cached" + return get_attribute(TropL,:algebraic_pluecker_vector) +end + + +@doc raw""" + tropical_semiring_map(TropL::TropicalLinearSpace) + +Return the tropical semiring map used to construct `TropL`. Raises an error, if it is not cached. +""" +function tropical_semiring_map(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:tropical_semiring_map) "no tropical semiring map cached" + return get_attribute(TropL,:tropical_semiring_map) end -### -# 3. Basic properties -# ------------------- -### +@doc raw""" + tropical_matrix(TropL::TropicalLinearSpace) + +Return the tropical matrix used to construct `TropL`. Raises an error, if it is not cached. +""" +function tropical_matrix(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:tropical_matrix) "no tropical matrix cached" + return get_attribute(TropL,:tropical_matrix) +end + + +@doc raw""" + algebraic_matrix(TropL::TropicalLinearSpace) + +Return the matrix over a valued field used to construct `TropL`. Raises an error, if it is not cached. +""" +function algebraic_matrix(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:algebraic_matrix) "no algebraic matrix cached" + return get_attribute(TropL,:algebraic_matrix) +end + + +@doc raw""" + algebraic_ideal(TropL::TropicalLinearSpace) + +Return the polynomial ideal over a valued field used to construct `TropL`. Raises an error, if it is not cached. +""" +function algebraic_ideal(TropL::TropicalLinearSpace) + @req has_attribute(TropL,:algebraic_ideal) "no algebraic ideal cached" + return get_attribute(TropL,:algebraic_ideal) +end diff --git a/src/TropicalGeometry/matrix.jl b/src/TropicalGeometry/matrix.jl new file mode 100644 index 000000000000..ff102439516f --- /dev/null +++ b/src/TropicalGeometry/matrix.jl @@ -0,0 +1,43 @@ +################################################################################ +# +# Tropical matrices +# +################################################################################ + + +################################################################################ +# +# Substraction-less tropical alternatives to generic functions +# +################################################################################ + +@doc raw""" + det(A::Generic.MatSpaceElem{<: TropicalSemiringElem}) + +Return the tropical determinant of `A`. + +!!! note + This function effectively overwrites the `det` command for tropical matrices. This means that functions like `minors` will use the tropical determinant when used on a tropical matrix. + +# Examples +```jldoctest +julia> A = matrix(tropical_semiring(),[1 2; 3 4]) +[(1) (2)] +[(3) (4)] + +julia> det(A) +(5) +``` +""" +function det(A::Generic.MatSpaceElem{<:TropicalSemiringElem}) + detA = zero(base_ring(A)) + nrows(A)!=ncols(A) && return detA # return tropical zero if matrix not square + for sigma in AbstractAlgebra.SymmetricGroup(nrows(A)) # otherwise follow Leibniz Formula + detA += prod([ A[i,sigma[i]] for i in 1:nrows(A) ]) + end + return detA +end + +function det(A::Matrix{TropicalSemiringElem{minOrMax}}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return det(matrix(TropicalSemiring{minOrMax},A)) +end diff --git a/src/TropicalGeometry/poly.jl b/src/TropicalGeometry/poly.jl index b4a31ef44253..8d72440a78fd 100644 --- a/src/TropicalGeometry/poly.jl +++ b/src/TropicalGeometry/poly.jl @@ -1,89 +1,264 @@ +################################################################################ +# +# Tropical polynomials +# +################################################################################ + + +################################################################################ +# +# Tropical alternatives to generic functions +# +################################################################################ + ### -# Tropical polynomial computations in Oscar -# ========================================= +# Alternatives to generic functions that use R(1) and R(0) instead of one(R) and zero(R) ### +one(R::Generic.PolyRing{<:TropicalSemiringElem}) = R(one(base_ring(R))) +zero(R::Generic.PolyRing{<:TropicalSemiringElem}) = R(zero(base_ring(R))) +one(R::MPolyRing{<:TropicalSemiringElem}) = R(one(base_ring(R))) +zero(R::MPolyRing{<:TropicalSemiringElem}) = R(zero(base_ring(R))) -@doc raw""" - tropical_polynomial(f::MPolyRingElem,M::Union{typeof(min),typeof(max)}=min) +function polynomial_ring(R::TropicalSemiring, s::Symbol; cached::Bool = true) + T = elem_type(R) + parent_obj = Oscar.Generic.PolyRing{T}(R, s, cached) + return parent_obj, parent_obj([zero(R), one(R)]) +end -Given a polynomial `f` over a field with an intrinsic valuation (i.e., a field -on which a function `valuation` is defined such as `PadicField(7,2)`), -returns the tropicalization of `f` as a polynomial over the min tropical semiring -(default) or the max tropical semiring. -# Examples -```jldoctest -julia> K = PadicField(7, 2) -Field of 7-adic numbers +### +# Alternative to generic prints that display zero sums as 0 +### +function AbstractAlgebra.expressify(@nospecialize(a::PolyRingElem{<:TropicalSemiringElem}), x = var(parent(a)); context = nothing) + if iszero(a) + return expressify(zero(base_ring(a)), context = context) + end + sum = Expr(:call, :+) + for k in degree(a):-1:0 + c = coeff(a, k) + if !iszero(c) + xk = k < 1 ? expressify(one(base_ring(a)), context = context) : k == 1 ? x : Expr(:call, :^, x, k) + if isone(c) + push!(sum.args, Expr(:call, :*, xk)) + else + push!(sum.args, Expr(:call, :*, expressify(c, context = context), xk)) + end + end + end + return sum +end +function AbstractAlgebra.expressify(a::MPolyRingElem{<:TropicalSemiringElem}, x = symbols(parent(a)); context = nothing) + if iszero(a) + return expressify(zero(base_ring(a)), context = context) + end + sum = Expr(:call, :+) + n = nvars(parent(a)) + for (c, v) in zip(coefficients(a), exponents(a)) + prod = Expr(:call, :*) + if !isone(c) + push!(prod.args, expressify(c, context = context)) + end + for i in 1:n + if v[i] > 1 + push!(prod.args, Expr(:call, :^, x[i], v[i])) + elseif v[i] == 1 + push!(prod.args, x[i]) + end + end + # Capture empty products + if length(prod.args) == 1 + prod = expressify(one(base_ring(a)), context = context) + end + push!(sum.args, prod) + end + return sum +end -julia> Kxy, (x,y) = K["x", "y"] -(Multivariate polynomial ring in 2 variables over QQ_7, AbstractAlgebra.Generic.MPoly{padic}[x, y]) -julia> f = 7*x+y+49 -(7^1 + O(7^3))*x + y + 7^2 + O(7^4) +### +# Disabling ideals in tropical polyomial rings +### +function MPolyIdeal(R::Ring, g::Vector{Generic.MPoly{TropicalSemiringElem{minOrMax}}}) where {minOrMax} + error("Ideals over tropical semirings not supported") +end -julia> tropical_polynomial(f,min) -(1)*x + y + (2) -julia> tropical_polynomial(f,max) -(-1)*x + y + (-2) + +################################################################################ +# +# @tropical macro +# +################################################################################ + +""" + @tropical(expr) + +Translate the expression in the tropical world. + +# Examples + +```jlexample +julia> T = tropical_semiring(min); + +julia> Tx, x = Tropical.polynomial_ring(T, "x" => 1:3); + +julia> @tropical min(1, x[1], x[2], 2*x[3]) +x[1] + x[2] + x[3]^2 + (1) ``` """ -function tropical_polynomial(f::MPolyRingElem, M::Union{typeof(min),typeof(max)}=min) - T = TropicalSemiring(M) - if M==min - s=1 - else - s=-1 - end - - Tx,x = polynomial_ring(T,[repr(x) for x in gens(parent(f))]) - tropf = inf(T) - - if base_ring(parent(f)) isa NonArchLocalField - for (c,alpha) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f)) - tropf = tropf + T(s*valuation(c))*monomial(Tx,alpha) +macro tropical(expr) + e = _tropicalize(expr) + return quote + $(esc(e)) end - else - for alpha in AbstractAlgebra.exponent_vectors(f) - tropf = tropf + T(0)*monomial(Tx,alpha) +end + +_tropicalize(x::Symbol) = x + +_tropicalize(x::Int) = x + +function _tropicalize(x::Expr) + if x.head == :call + if x.args[1] == :min + x.args[1] = :(+) + elseif x.args[1] == :(*) + length(x.args) <= 3 || error("Cannot convert") + x.args[1] = :(Tropical._tropical_mul) + elseif x.args[1] == :(+) + x.args[1] = :* + else + error("Cannot convert") + end + for i in 2:length(x.args) + x.args[i] = _tropicalize(x.args[i]) + end + else + return x end - end + return x +end - return tropf +function _tropical_mul(x, y) + if x isa Union{Integer, Rational, QQFieldElem, ZZRingElem} + if x isa Rational || x isa QQFieldElem + _x = ZZ(x) + return y^_x + else + return y^x + end + elseif y isa Union{Integer, Rational, QQFieldElem, ZZRingElem} + if y isa Rational | y isa QQFieldElem + _y = ZZ(y) + return x^_y + else + return x^y + end + else + error("Cannot convert ", x, " * ", y) + end end +################################################################################ +# +# Conversion to tropical polynomial +# +################################################################################ + @doc raw""" - tropical_polynomial(f::MPolyRingElem,val::TropicalSemiringMap) + tropical_polynomial(f::MPolyRingElem,nu::TropicalSemiringMap) -Given a polynomial `f` and a tropical semiring map `val`, -returns the tropicalization of `f` as a polynomial over the tropical semiring. +Given a polynomial `f` and a tropical semiring map `nu`, +return the tropicalization of `f` as a polynomial over the tropical semiring. # Examples ```jldoctest julia> R, (x,y) = polynomial_ring(QQ,["x", "y"]) (Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y]) -julia> val = TropicalSemiringMap(QQ,7) -The 7-adic valuation on Rational field +julia> nu = tropical_semiring_map(QQ,7) +Map into Min tropical semiring encoding the 7-adic valuation on Rational field julia> f = 7*x+y+49 7*x + y + 49 -julia> tropical_polynomial(f,val) +julia> tropical_polynomial(f,nu) (1)*x + y + (2) ``` """ -function tropical_polynomial(f::MPolyRingElem, val::TropicalSemiringMap) - T = TropicalSemiring(val) - Tx,x = polynomial_ring(T,[repr(x) for x in gens(parent(f))]) - tropf = inf(T) +function tropical_polynomial(f::MPolyRingElem, nu::Union{Nothing,TropicalSemiringMap}=nothing) - for (c,alpha) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f)) - tropf = tropf + val(c)*monomial(Tx,alpha) - end + # if unspecified, set nu to be the trivial valuation + min convention + isnothing(nu) && (nu = tropical_semiring_map(parent(f))) + + T = tropical_semiring(nu) + Tx,x = polynomial_ring(T,[repr(x) for x in gens(parent(f))]) + tropf = inf(T) + + for (c,alpha) in zip(coefficients(f), exponents(f)) + tropf = tropf + nu(c)*monomial(Tx,alpha) + end - return tropf + return tropf end + + + +################################################################################ +# +# Outdated code +# +################################################################################ + +# # Disabled due to potential clash with +# # tropical_polynomial(f::MPolyRingElem, nu::Union{Nothing,TropicalSemiringMap}=nothing) +# @doc raw""" +# tropical_polynomial(f::MPolyRingElem,M::Union{typeof(min),typeof(max)}=min) + +# Given a polynomial `f` over a field with an intrinsic valuation (i.e., a field +# on which a function `valuation` is defined such as `PadicField(7,2)`), +# return the tropicalization of `f` as a polynomial over the min tropical semiring +# (default) or the max tropical semiring. + +# # Examples +# ```jldoctest +# julia> K = PadicField(7, 2) +# Field of 7-adic numbers + +# julia> Kxy, (x,y) = K["x", "y"] +# (Multivariate polynomial ring in 2 variables over QQ_7, AbstractAlgebra.Generic.MPoly{padic}[x, y]) + +# julia> f = 7*x+y+49 +# (7^1 + O(7^3))*x + y + 7^2 + O(7^4) + +# julia> tropical_polynomial(f,min) +# (1)*x + y + (2) + +# julia> tropical_polynomial(f,max) +# (-1)*x + y + (-2) +# ``` +# """ +# function tropical_polynomial(f::MPolyRingElem, M::Union{typeof(min),typeof(max)}=min) +# T = tropical_semiring(M) +# if M==min +# s=1 +# else +# s=-1 +# end + +# Tx,x = polynomial_ring(T,[repr(x) for x in gens(parent(f))]) +# tropf = inf(T) + +# if base_ring(parent(f)) isa NonArchLocalField +# for (c,alpha) in zip(coefficients(f), exponents(f)) +# tropf = tropf + T(s*valuation(c))*monomial(Tx,alpha) +# end +# else +# for alpha in exponents(f) +# tropf = tropf + T(0)*monomial(Tx,alpha) +# end +# end + +# return tropf +# end diff --git a/src/TropicalGeometry/semiring.jl b/src/TropicalGeometry/semiring.jl index 858ae8e786b7..29cb2ba9e648 100644 --- a/src/TropicalGeometry/semiring.jl +++ b/src/TropicalGeometry/semiring.jl @@ -1,60 +1,92 @@ -import Base.string -# module Tropical - -# import Oscar: expressify, Ring, @enable_all_show_via_expressify, zero, one, iszero, isone, polynomial_ring - ################################################################################ # -# Types +# Tropical semirings and tropical semiring elements (= tropical numbers) # ################################################################################ -# We use T to record whether we are in the min/max case -# T is either typeof(min) or typeof(max) -struct TropicalSemiring{T} <: Field +# minOrMax distinguishes between the min-plus and max-plus semiring +struct TropicalSemiring{minOrMax<:Union{typeof(min),typeof(max)}} <: Field end -# We use the flag isinf to denote +/- infinity -# todo: should this be called TropicalNumber instead? -# I have no preference, except that it should be consistent with the other libraries, -# e.g. what are elements of p-adic number rings called? -mutable struct TropicalSemiringElem{T} <: FieldElem - parent::TropicalSemiring{T} - isinf::Bool - data::QQFieldElem - - function rational_value(t::TropicalSemiringElem) - return t.data - end - - function TropicalSemiringElem(R::TropicalSemiring{T}, isinf::Bool) where {T} - @assert isinf - z = new{T}() - z.isinf = true - z.parent = R - return z - end - - function TropicalSemiringElem(R::TropicalSemiring{T}, x::RingElem) where {T} - return new{T}(R, false, x) - end +mutable struct TropicalSemiringElem{minOrMax<:Union{typeof(min),typeof(max)}} <: FieldElem + parent::TropicalSemiring{minOrMax} + isinf::Bool # distinguishes between ±∞ and other tropical numbers + data::QQFieldElem + + function TropicalSemiringElem(R::TropicalSemiring{minOrMax}, isinf::Bool) where {minOrMax<:Union{typeof(min),typeof(max)}} + @assert isinf + return new{minOrMax}(R, true) + end + + function TropicalSemiringElem(R::TropicalSemiring{minOrMax}, x::RingElem) where {minOrMax<:Union{typeof(min),typeof(max)}} + return new{minOrMax}(R, false, x) + end end # Type gymnastics +elem_type(::Type{TropicalSemiring{minOrMax}}) where {minOrMax<:Union{typeof(min),typeof(max)}} = TropicalSemiringElem{minOrMax} + +parent_type(::Type{TropicalSemiringElem{minOrMax}}) where {minOrMax<:Union{typeof(min),typeof(max)}} = TropicalSemiring{minOrMax} -Oscar.elem_type(::Type{TropicalSemiring{T}}) where {T} = TropicalSemiringElem{T} -Oscar.parent_type(::Type{TropicalSemiringElem{T}}) where {T} = TropicalSemiring{T} ################################################################################ # -# Constructors for the tropical semiring +# Basic access for tropical numbers # ################################################################################ +parent(x::TropicalSemiringElem) = x.parent + +data(x::TropicalSemiringElem) = x.data # undefined if x==±∞ + +isinf(x::TropicalSemiringElem) = x.isinf # also serves as test if x==±∞ + @doc raw""" + convention(T::TropicalSemiring) + +Return `min` if `T` is the min tropical semiring, +return `max` if `T` is the max tropical semiring. +Works similarly for tropical numbers, +tropical vectors and matrices, and tropical polynomials. + +# Examples +```jldoctest; filter = r"\(generic function with .* methods\)" +julia> T = tropical_semiring(min) +Min tropical semiring + +julia> convention(T) +min (generic function with 27 methods) + +julia> T = tropical_semiring(max) +Max tropical semiring + +julia> convention(T) +max (generic function with 27 methods) +``` +""" +convention(T::TropicalSemiring{typeof(min)}) = min +convention(T::TropicalSemiring{typeof(max)}) = max +convention(a::TropicalSemiringElem{typeof(min)}) = min +convention(a::TropicalSemiringElem{typeof(max)}) = max +convention(v::Vector{TropicalSemiringElem{typeof(min)}}) = min +convention(v::Vector{TropicalSemiringElem{typeof(max)}}) = max +convention(M::Vector{Vector{TropicalSemiringElem{typeof(min)}}}) = min +convention(M::Vector{Vector{TropicalSemiringElem{typeof(max)}}}) = max +convention(M::Generic.MatSpaceElem{TropicalSemiringElem{typeof(min)}}) = min +convention(M::Generic.MatSpaceElem{TropicalSemiringElem{typeof(max)}}) = max +convention(f::Generic.MPoly{TropicalSemiringElem{typeof(min)}}) = min +convention(f::Generic.MPoly{TropicalSemiringElem{typeof(max)}}) = max + + +################################################################################ +# +# Constructors for tropical semirings +# +################################################################################ - TropicalSemiring(M::Union{typeof(min),typeof(max)}=min) +@doc raw""" + tropical_semiring(M::Union{typeof(min),typeof(max)}=min) The tropical semiring with min (default) or max. @@ -63,13 +95,13 @@ The tropical semiring with min (default) or max. # Examples (basic arithmetic) ```jldoctest -julia> T = TropicalSemiring() # = TropicalSemiring(min) -Tropical semiring (min) +julia> T = tropical_semiring() # = tropical_semiring(min) +Min tropical semiring -julia> T = TropicalSemiring(max) -Tropical semiring (max) +julia> T = tropical_semiring(max) +Max tropical semiring -julia> 0*T(3) + 1*T(1)^2 + inf(T) # = max(0+3,1+2*1,-∞) +julia> 0*T(3) + 1*T(1)^2 + zero(T) # = max(0+3,1+2*1,-∞) (3) julia> T(0) == 0 # checks whether the tropical number is 0 @@ -81,157 +113,162 @@ false # Examples (polynomials) ```jldoctest -julia> T = TropicalSemiring() -Tropical semiring (min) +julia> T = tropical_semiring() +Min tropical semiring -julia> Tx,(x1,x2) = polynomial_ring(T,3) -(Multivariate polynomial ring in 3 variables over tropical semiring (min), AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}[x1, x2, x3]) +julia> Tx,(x1,x2) = polynomial_ring(T,2) +(Multivariate polynomial ring in 2 variables over min tropical semiring, AbstractAlgebra.Generic.MPoly{TropicalSemiringElem{typeof(min)}}[x1, x2]) julia> f = x1 + -1*x2 + 0 x1 + (-1)*x2 + (0) -julia> evaluate(f,[T(-1//2),T(1//2)]) # warning: omitting T(0) gives an error +julia> evaluate(f,T.([-1//2,1//2])) # warning: omitting T() gives an error (-1//2) ``` # Examples (matrices) ```jldoctest -julia> T = TropicalSemiring() -Tropical semiring (min) +julia> T = tropical_semiring() +Min tropical semiring -julia> A = [T(0) inf(T); inf(T) T(0)] # = tropical identity matrix -2×2 Matrix{Oscar.TropicalSemiringElem{typeof(min)}}: - (0) ∞ - ∞ (0) +julia> A = identity_matrix(T, 2) # = tropical identity matrix +[ (0) infty] +[infty (0)] julia> 2*A -2×2 Matrix{Oscar.TropicalSemiringElem{typeof(min)}}: - (2) ∞ - ∞ (2) +[ (2) infty] +[infty (2)] julia> A*A -2×2 Matrix{Oscar.TropicalSemiringElem{typeof(min)}}: - (0) ∞ - ∞ (0) +[ (0) infty] +[infty (0)] julia> det(A) (0) + +julia> minors(A,1) +4-element Vector{TropicalSemiringElem{typeof(min)}}: + (0) + infty + infty + (0) ``` """ -TropicalSemiring() = TropicalSemiring{typeof(min)}() -TropicalSemiring(::typeof(max)) = TropicalSemiring{typeof(max)}() -TropicalSemiring(::typeof(min)) = TropicalSemiring{typeof(min)}() +tropical_semiring() = TropicalSemiring{typeof(min)}() +tropical_semiring(::typeof(max)) = TropicalSemiring{typeof(max)}() +tropical_semiring(::typeof(min)) = TropicalSemiring{typeof(min)}() + + ################################################################################ # -# Constructors for elements +# Constructors for tropical numbers # ################################################################################ -function (R::TropicalSemiring)(u::TropicalSemiringElem) - @assert parent(u) === R +function (T::TropicalSemiring)(u::TropicalSemiringElem) + @req parent(u)==T "incompatible conventions" return u end -function (R::TropicalSemiring)(u::RingElem) - v = QQ(u) - @assert parent(v) === QQ - return TropicalSemiringElem(R, v) -end - -function (R::TropicalSemiring)(u::Union{Integer, Rational}) - return TropicalSemiringElem(R, QQ(u)) -end +zero(T::TropicalSemiring) = TropicalSemiringElem(T, true) # neutral element w.r.t. + -inf(R::TropicalSemiring) = TropicalSemiringElem(R, true) +one(T::TropicalSemiring) = TropicalSemiringElem(T, zero(QQ)) # neutral element w.r.t. * -Oscar.zero(T::TropicalSemiring) = inf(T) +inf(T::TropicalSemiring) = zero(T) -Oscar.one(R::TropicalSemiring) = R(zero(QQ)) +(T::TropicalSemiring)() = zero(T) -Oscar.zero(x::TropicalSemiringElem) = zero(parent(x)) -(R::TropicalSemiring)() = zero(R) ################################################################################ # -# Basic access +# Conversion between tropical numbers and rational numbers. +# If preserve_ordering==true and minOrMax==typeof(max), flip signs +# (for info on tropical semiring ordering see comparison below). # ################################################################################ -# The underlying rational number. This is undefined for inf. -data(x::TropicalSemiringElem) = x.data +function (R::TropicalSemiring{typeof(min)})(x::QQFieldElem; preserve_ordering::Bool=false) + return TropicalSemiringElem(R,x) +end -function string(x::TropicalSemiringElem) - if isinf(x) - return "infinity" - end - return string(data(x)) +function (R::TropicalSemiring{typeof(max)})(x::QQFieldElem; preserve_ordering::Bool=false) + return (preserve_ordering ? TropicalSemiringElem(R,-x) : TropicalSemiringElem(R,x)) end -# Test if something is inf. -isinf(x::TropicalSemiringElem) = x.isinf +function (R::TropicalSemiring)(x::Union{Integer, Rational}; preserve_ordering::Bool=false) + return R(QQ(x),preserve_ordering=preserve_ordering) +end -Oscar.parent(x::TropicalSemiringElem{T}) where T = TropicalSemiring{T}() +function (R::TropicalSemiring)(x::RingElem; preserve_ordering::Bool=false) + x = QQ(x) + @req parent(x)==QQ "cannot convert object of type $(repr(typeof(x)))" + return R(x, preserve_ordering=preserve_ordering) +end -@doc raw""" - convention(T::TropicalSemiring) +function (::QQField)(x::TropicalSemiringElem{typeof(min)}; preserve_ordering::Bool=false) + @req !iszero(x) "cannot convert $(repr(x))" + return data(x) +end -Return `min` if `T` is the min tropical semiring, -return `max` if `T` is the max tropical semiring. +function (::QQField)(x::TropicalSemiringElem{typeof(max)}; preserve_ordering::Bool=false) + @req !iszero(x) "cannot convert $(repr(x))" + return (preserve_ordering ? -data(x) : data(x)) +end -# Examples -```jldoctest; filter = r"\(generic function with [0-9]+ methods\)" -julia> T = TropicalSemiring(min) -Tropical semiring (min) +function (::ZZRing)(x::TropicalSemiringElem; preserve_ordering::Bool=false) + return ZZ(QQ(x,preserve_ordering=preserve_ordering)) +end -julia> convention(T) -min (generic function with 12 methods) +function (::Type{Int})(x::TropicalSemiringElem; preserve_ordering::Bool=false) + return Int(QQ(x,preserve_ordering=preserve_ordering)) +end + +function (::Type{Rational})(x::TropicalSemiringElem; preserve_ordering::Bool=false) + return Rational(QQ(x,preserve_ordering=preserve_ordering)) +end -julia> T = TropicalSemiring(max) -Tropical semiring (max) -julia> convention(T) -max (generic function with 14 methods) -``` -""" -convention(x::TropicalSemiring{typeof(min)}) = min -convention(x::TropicalSemiring{typeof(max)}) = max ################################################################################ # -# Printing +# Copying # ################################################################################ -# Hook into the fancy printing +Base.copy(a::TropicalSemiringElem) = a -# We use (x) for finite values and ±∞ for infinity. -function AbstractAlgebra.expressify(x::TropicalSemiringElem{T}; context = nothing) where {T} - if isinf(x) - return T === typeof(min) ? "∞" : "-∞" - end - return Expr(:call, "", expressify(data(x), context = context)) +function Base.deepcopy_internal(x::TropicalSemiringElem, dict::IdDict) + isinf(x) ? (return inf(parent(x))) : (return TropicalSemiringElem(x.parent, Base.deepcopy_internal(data(x), dict))) end -AbstractAlgebra.expressify(R::TropicalSemiring{typeof(min)}; context = nothing) = "Tropical semiring (min)" - -AbstractAlgebra.expressify(R::TropicalSemiring{typeof(max)}; context = nothing) = "Tropical semiring (max)" - -@enable_all_show_via_expressify TropicalSemiringElem - -@enable_all_show_via_expressify TropicalSemiring ################################################################################ # -# Predicates +# Printing # ################################################################################ -Oscar.iszero(x::TropicalSemiringElem) = isinf(x) +# Hook into the fancy printing, we use (x) for finite values and ±∞ for infinity. +function AbstractAlgebra.expressify(x::TropicalSemiringElem{minOrMax}; context = nothing) where {minOrMax<:Union{typeof(min),typeof(max)}} + if isinf(x) + if Oscar.is_unicode_allowed() + return minOrMax==typeof(min) ? "∞" : "-∞" + else + return minOrMax==typeof(min) ? "infty" : "-infty" + end + end + return Expr(:call, "", expressify(data(x), context = context)) +end + +AbstractAlgebra.expressify(R::TropicalSemiring{typeof(min)}; context = nothing) = "Min tropical semiring" +AbstractAlgebra.expressify(R::TropicalSemiring{typeof(max)}; context = nothing) = "Max tropical semiring" +@enable_all_show_via_expressify TropicalSemiringElem +@enable_all_show_via_expressify TropicalSemiring + -Oscar.isone(x::TropicalSemiringElem) = !isinf(x) && iszero(data(x)) ################################################################################ # @@ -247,376 +284,127 @@ end function Base.hash(x::TropicalSemiringElem, h::UInt) b = 0x4df38853cc07aa27 % UInt - h = hash(isinf(x), h) - if !isinf(x) - h = hash(data(x), h) - end + h = (isinf(x) ? hash(isinf(x), h) : hash(data(x), h)) return xor(h, b) end -################################################################################ -# -# Comparison -# * min is ordered as usual: -inf < ... < -1 < 0 < 1 < ... -# * max is ordered reversely: ... > -1 > 0 > 1 > ... > inf -# (see Section 2.7 in Joswig: "Essentials of Tropical Combinatorics" -# -################################################################################ - -function isless(x::TropicalSemiringElem{typeof(min)}, y::TropicalSemiringElem{typeof(min)}) - if isinf(x) - return false # x=-inf, no y is smaller - end - if isinf(y) - return true # y=-inf, smaller than all x except x=-inf, which was handled above - end - return data(x) < data(y) -end -function isless(x::TropicalSemiringElem{typeof(max)}, y::TropicalSemiringElem{typeof(max)}) - if isinf(x) - return false # x=inf, no y is smaller - end - if isinf(y) - return true # y=inf, smaller than all x except x=inf, which was handled above - end - return data(x) > data(y) -end ################################################################################ # -# Copying +# Predicates +# (see also isinf in basic access) # ################################################################################ -Base.copy(a::TropicalSemiringElem) = a +iszero(x::TropicalSemiringElem) = isinf(x) -function Base.deepcopy_internal(x::TropicalSemiringElem, dict::IdDict) - if !isinf(x) - return TropicalSemiringElem(x.parent, Base.deepcopy_internal(data(x), dict)) - else - return inf(parent(x)) - end -end +isone(x::TropicalSemiringElem) = !isinf(x) && iszero(data(x)) -################################################################################ -# -# Addition -# -################################################################################ -function Base.:(+)(x::TropicalSemiringElem{T}, y::TropicalSemiringElem{T}) where {T} - isinf(x) && return deepcopy(y) - isinf(y) && return deepcopy(x) - return parent(x)(convention(parent(x))(data(x), data(y))) -end ################################################################################ # -# Multiplication +# Comparison +# * min-plus semiring is ordered as usual: -inf < ... < -1 < 0 < 1 < ... +# * max-plax semiring is ordered in reverse: ... > -1 > 0 > 1 > ... > inf +# (see Section 2.7 in Joswig: "Essentials of Tropical Combinatorics") # ################################################################################ -function Base.:(*)(x::TropicalSemiringElem{T}, y::TropicalSemiringElem{T}) where {T} - if isinf(x) - return x - else - if isinf(y) - return y - else - return parent(x)(data(x) + data(y)) - end - end +function isless(x::TropicalSemiringElem{typeof(min)}, y::TropicalSemiringElem{typeof(min)}) + iszero(x) && return false # x=-inf, no y is smaller + iszero(y) && return true # y=-inf, smaller than all x except x=-inf, which was handled above + return data(x) < data(y) end -################################################################################ -# -# Division / Inversion -# -################################################################################ - -function divexact(a::TropicalSemiringElem{T}, b::TropicalSemiringElem{T}) where T <: FieldElement - if iszero(b) - error("dividing by (tropical) zero") - end - if iszero(a) - return a - end - return parent(a)(data(a)-data(b)) +function isless(x::TropicalSemiringElem{typeof(max)}, y::TropicalSemiringElem{typeof(max)}) + iszero(x) && return false # x=inf, no y is smaller + iszero(y) && return true # y=inf, smaller than all x except x=inf, which was handled above + return data(x) > data(y) end -function inv(a::TropicalSemiringElem{T}) where T <: FieldElem - if iszero(a) - error("inverting (tropical) zero") - end - return parent(a)(-data(a)) -end -function Base.:(//)(a::TropicalSemiringElem{T}, b::TropicalSemiringElem{T}) where {T} - if iszero(b) - error("dividing by (tropical) zero") - end - if iszero(a) - return a - end - return parent(a)(data(a)-data(b)) -end ################################################################################ # -# Powering +# Arithmetics # ################################################################################ -function Base.:(^)(a::TropicalSemiringElem, n::Int) - return Base.power_by_squaring(a, n) +function Base.:(+)(x::TropicalSemiringElem{minOrMax}, y::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + iszero(x) && return deepcopy(y) # if x is zero, return y + iszero(y) && return deepcopy(x) # if y is zero, return x + return parent(x)(convention(parent(x))(data(x), data(y))) # otherwise, return their min / max end -################################################################################ -# -# Disable subtraction -# -################################################################################ - function Base.:(-)(x::TropicalSemiringElem, y::TropicalSemiringElem...) error("Tropical subtraction not defined (use tropical division for classical subtraction)") end -################################################################################ -# -# Unsafe operations -# -################################################################################ - -Oscar.mul!(x::TropicalSemiringElem, y::TropicalSemiringElem, z::TropicalSemiringElem) = y * z - -Oscar.addeq!(y::TropicalSemiringElem, z::TropicalSemiringElem) = y + z - -################################################################################ -# -# Conversions -# -################################################################################ - -# converts an element x of the tropical semiring to Int -# throws an error if x is infinity / -infinity -# preserves ordering if preserve_ordering==true (default: false), -# meaning that given x in the max-plus semiring returns -x -# meaning that the actual valuation of x is returned -function (::Type{Int})(x::TropicalSemiringElem{typeof(min)}; preserve_ordering::Bool=false) - @assert !iszero(x) - return Int(ZZ(data(x))) -end -function (::Type{Int})(x::TropicalSemiringElem{typeof(max)}; preserve_ordering::Bool=false) - @assert !iszero(x) - if preserve_ordering - return -Int(ZZ(data(x))) - end - return Int(ZZ(data(x))) +function Base.:(*)(x::TropicalSemiringElem{minOrMax}, y::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + iszero(x) && return x # if x is zero, return it + iszero(y) && return y # if y is zero, return it + return parent(x)(data(x) + data(y)) # otherwise, return their sum end -################################################################################ -# -# Determinant -# -################################################################################ - -function det(x::AbstractAlgebra.Generic.MatSpaceElem{Oscar.TropicalSemiringElem{T}}) where {T} - R = base_ring(x) - S = AbstractAlgebra.SymmetricGroup(nrows(x)) - res = zero(R) - for s in S - o = one(R) - for i in 1:nrows(x) - o = o * x[i, s[i]] - end - res = res + o - end - return res +function divexact(x::TropicalSemiringElem{minOrMax}, y::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + @req !iszero(y) "dividing by (tropical) zero" + return (iszero(x) ? x : parent(x)(data(x)-data(y))) end -function det(x::Matrix{Oscar.TropicalSemiringElem{T}}) where {T} - if length(x)==0 - if T == typeof(min) - return TropicalSemiring(min)(1) - else - return TropicalSemiring(max)(1) - end - end - - return det(matrix(parent(x[1,1]),x)) +function Base.:(//)(x::TropicalSemiringElem{minOrMax}, y::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return divexact(x,y) end - - -################################################################################ -# -# Tropical Minors -# -################################################################################ -@doc raw""" - tropical_minors(A::MatElem, k::Int) - -Return an array consisting of the k-minors of a tropical matrix `A`. -""" -function tropical_minors(A::MatElem, k::Int) - row_indices = AbstractAlgebra.combinations(nrows(A), k) - col_indices = AbstractAlgebra.combinations(ncols(A), k) - mins = Vector{elem_type(base_ring(A))}(undef, 0) - for ri in row_indices - for ci in col_indices - push!(mins, determinant(A[ri, ci])) - end - end - return(mins) +function Base.:(/)(x::TropicalSemiringElem{minOrMax}, y::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return divexact(x,y) end - - -################################################################################ -# -# Polynomials -# -################################################################################ - -# The generic functions use R(1) and R(0), which is bad. -one(R::AbstractAlgebra.Generic.PolyRing{<:TropicalSemiringElem}) = R(one(base_ring(R))) - -zero(R::AbstractAlgebra.Generic.PolyRing{TropicalSemiringElem{S}}) where {S} = R(zero(base_ring(R))) - -function Oscar.polynomial_ring(R::TropicalSemiring, s::Symbol; cached::Bool = true) - T = elem_type(R) - parent_obj = Oscar.Generic.PolyRing{T}(R, s, cached) - - return parent_obj, parent_obj([zero(R), one(R)]) +function inv(a::TropicalSemiringElem) + @req !iszero(a) "inverting (tropical) zero" + return parent(a)(-data(a)) end -# Oscar will print zero sums as 0, which we do not want. -# So we have to adjust the printing code for polynomials -function AbstractAlgebra.expressify(@nospecialize(a::PolyRingElem{<:TropicalSemiringElem}), - x = var(parent(a)); context = nothing) - if iszero(a) - return expressify(zero(base_ring(a)), context = context) - end - sum = Expr(:call, :+) - for k in degree(a):-1:0 - c = coeff(a, k) - if !iszero(c) - xk = k < 1 ? expressify(one(base_ring(a)), context = context) : k == 1 ? x : Expr(:call, :^, x, k) - if isone(c) - push!(sum.args, Expr(:call, :*, xk)) - else - push!(sum.args, Expr(:call, :*, expressify(c, context = context), xk)) - end +function Base.:(^)(a::TropicalSemiringElem, n::QQFieldElem) + if iszero(a) + @req n>0 "dividing by (tropical) zero" + return zero(parent(a)) # if a is zero, return zero end - end - return sum + return parent(a)(data(a)*n) # otherwise (rational) multiply a by n end -# As above, now for multivariate polynomials -function AbstractAlgebra.expressify(a::MPolyRingElem{<:TropicalSemiringElem}, x = symbols(parent(a)); context = nothing) - if iszero(a) - return expressify(zero(base_ring(a)), context = context) - end - sum = Expr(:call, :+) - n = nvars(parent(a)) - for (c, v) in zip(AbstractAlgebra.coefficients(a), AbstractAlgebra.exponent_vectors(a)) - prod = Expr(:call, :*) - if !isone(c) - push!(prod.args, expressify(c, context = context)) +function Base.:(^)(a::TropicalSemiringElem, n::ZZRingElem) + if iszero(a) + @req n>0 "dividing by (tropical) zero" + return zero(parent(a)) # if a is zero, return zero end - for i in 1:n - if v[i] > 1 - push!(prod.args, Expr(:call, :^, x[i], v[i])) - elseif v[i] == 1 - push!(prod.args, x[i]) - end + return parent(a)(data(a)*n) # otherwise (rational) multiply a by n +end + +function Base.:(^)(a::TropicalSemiringElem, n::Rational) + if iszero(a) + @req n>0 "dividing by (tropical) zero" + return zero(parent(a)) # if a is zero, return zero end - # Capture empty products - if length(prod.args) == 1 - prod = expressify(one(base_ring(a)), context = context) + return parent(a)(data(a)*n) # otherwise (rational) multiply a by n +end + +function Base.:(^)(a::TropicalSemiringElem, n::Integer) + if iszero(a) + @req n>0 "dividing by (tropical) zero" + return zero(parent(a)) # if a is zero, return zero end - push!(sum.args, prod) - end - return sum + return parent(a)(data(a)*n) # otherwise (rational) multiply a by n end -one(R::AbstractAlgebra.Generic.MPolyRing{<:TropicalSemiringElem}) = R(one(base_ring(R))) -zero(R::AbstractAlgebra.Generic.MPolyRing{<:TropicalSemiringElem}) = R(zero(base_ring(R))) ################################################################################ # -# @tropical macro +# Unsafe operations # ################################################################################ -""" - @tropical(expr) - -Translate the expression in the tropical world. - -# Examples - -```jlexample -julia> T = TropicalSemiring(min); - -julia> Tx, x = Tropical.polynomial_ring(T, "x" => 1:3); - -julia> @tropical min(1, x[1], x[2], 2*x[3]) -x[1] + x[2] + x[3]^2 + (1) -``` -""" -macro tropical(expr) - e = _tropicalize(expr) - return quote - $(esc(e)) - end -end - -_tropicalize(x::Symbol) = x - -_tropicalize(x::Int) = x - -function _tropicalize(x::Expr) - if x.head == :call - if x.args[1] == :min - x.args[1] = :(+) - elseif x.args[1] == :(*) - length(x.args) <= 3 || error("Cannot convert") - x.args[1] = :(Tropical._tropical_mul) - elseif x.args[1] == :(+) - x.args[1] = :* - else - error("Cannot convert") - end - for i in 2:length(x.args) - x.args[i] = _tropicalize(x.args[i]) - end - else - return x - end - return x -end - -function _tropical_mul(x, y) - if x isa Union{Integer, Rational, QQFieldElem, ZZRingElem} - if x isa Rational || x isa QQFieldElem - _x = ZZ(x) - return y^_x - else - return y^x - end - elseif y isa Union{Integer, Rational, QQFieldElem, ZZRingElem} - if y isa Rational | y isa QQFieldElem - _y = ZZ(y) - return x^_y - else - return x^y - end - else - error("Cannot convert ", x, " * ", y) - end -end - -# end # module +Oscar.mul!(x::TropicalSemiringElem, y::TropicalSemiringElem, z::TropicalSemiringElem) = y * z +Oscar.addeq!(y::TropicalSemiringElem, z::TropicalSemiringElem) = y + z diff --git a/src/TropicalGeometry/semiring_map.jl b/src/TropicalGeometry/semiring_map.jl new file mode 100644 index 000000000000..50b339f016d6 --- /dev/null +++ b/src/TropicalGeometry/semiring_map.jl @@ -0,0 +1,255 @@ +################################################################################ +# +# Tropical semiring maps +# ====================== +# maps from a field K to a tropical semiring T with the purpose of encoding +# - a valuation on K +# - a choice of min- or max-convention +# +################################################################################ +struct TropicalSemiringMap{typeofValuedField,typeofUniformizer,minOrMax} + valued_field::typeofValuedField + uniformizer::typeofUniformizer + tropical_semiring::TropicalSemiring +end + + + +################################################################################ +# +# Properties +# +################################################################################ +valued_field(nu::TropicalSemiringMap) = nu.valued_field +uniformizer(nu::TropicalSemiringMap) = nu.uniformizer +tropical_semiring(nu::TropicalSemiringMap) = nu.tropical_semiring +convention(nu::TropicalSemiringMap) = convention(tropical_semiring(nu)) + + + +################################################################################ +# +# Trivial valuation on any field +# +################################################################################ + +# Constructor: +@doc raw""" + tropical_semiring_map(K::Field, minOrMax::Union{typeof(min),typeof(max)}=min) + +Return a map `nu` from `K` to the min (default) or max tropical semiring `T` such that `nu(0)=zero(T)` and `nu(c)=one(T)` for `c` non-zero. In other words, `nu` extends the trivial valuation on `K`. + +# Example +```jldoctest +julia> nu = tropical_semiring_map(QQ) # arbitrary rings possible +Map into Min tropical semiring encoding the trivial valuation on Rational field + +julia> nu(1) +(0) + +julia> nu(0) +infty + +julia> nu = tropical_semiring_map(QQ,max) # arbitrary rings possible +Map into Max tropical semiring encoding the trivial valuation on Rational field + +julia> nu(1) +(0) + +julia> nu(0) +-infty + +``` +""" +function tropical_semiring_map(K::Field, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalSemiringMap{typeof(K),Nothing,typeof(minOrMax)}(K,nothing,tropical_semiring(minOrMax)) +end + +# display: +function Base.show(io::IO, nu::TropicalSemiringMap{K,Nothing,minOrMax} where {K<:Ring, minOrMax<:Union{typeof(min),typeof(max)}}) + print(io, "Map into $(tropical_semiring(nu)) encoding the trivial valuation on $(valued_field(nu))") +end + +# evaluation: +function (nu::TropicalSemiringMap{K,Nothing,minOrMax})(c::Union{RingElem,Integer,Rational}) where {K<:Field, minOrMax<:Union{typeof(min),typeof(max)}} + return (iszero(valued_field(nu)(c)) ? inf(tropical_semiring(nu)) : one(tropical_semiring(nu))) +end + +# valued ring: +function valued_ring(nu::TropicalSemiringMap{K,Nothing,minOrMax}) where {K,minOrMax<:Union{typeof(min),typeof(max)}} + return valued_field(nu) +end + +# residue field: +function residue_field(nu::TropicalSemiringMap{K,Nothing,minOrMax}) where {K,minOrMax<:Union{typeof(min),typeof(max)}} + return valued_field(nu) +end + +# initial: +function initial(c::RingElem, nu::TropicalSemiringMap{K,Nothing,minOrMax}) where {K,minOrMax<:Union{typeof(min),typeof(max)}} + return residue_field(nu)(c) +end + + + +################################################################################ +# +# p-adic valuation on QQ +# +################################################################################ + +# Constructor: +@doc raw""" + tropical_semiring_map(QQ::QQField, p::QQFieldElem, minOrMax::Union{typeof(min),typeof(max)}=min) + +Return a map `nu` from `QQ` to the min (default) or max tropical semiring `T` such that `nu(0)=zero(T)` and `nu(c)=+/-val(c)` for `c` non-zero, where `val` denotes the `p`-adic valuation. Requires `p` to be a prime. + +# Example +```jldoctest +julia> nu_2 = tropical_semiring_map(QQ,2) +Map into Min tropical semiring encoding the 2-adic valuation on Rational field + +julia> nu_2(4) +(2) + +julia> nu_2(1//4) +(-2) + +julia> nu_2 = tropical_semiring_map(QQ,2,max); + +julia> nu_2(4) +(-2) + +julia> nu_2(1//4) +(2) + +``` +""" +function tropical_semiring_map(K::QQField, p::Union{RingElem,Integer,Rational}, minOrMax::Union{typeof(min),typeof(max)}=min) + p = ZZ(p) + @req isprime(ZZ(p)) "input p not prime" + @req p < 2^63-1 "input p may not exceed 2^63" + return TropicalSemiringMap{typeof(K),typeof(p),typeof(minOrMax)}(K,p,tropical_semiring(minOrMax)) +end + +# Display: +function Base.show(io::IO, nu::TropicalSemiringMap{QQField,ZZRingElem,minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + print(io, "Map into $(tropical_semiring(nu)) encoding the $(uniformizer(nu))-adic valuation on $(valued_field(nu))") +end + +# Evaluation: +function (nu::TropicalSemiringMap{QQField,ZZRingElem,typeof(min)})(c::Union{RingElem,Integer,Rational}) + c = valued_field(nu)(c) + iszero(c) && return zero(tropical_semiring(nu)) # if input is zero, return tropical zero + return tropical_semiring(nu)(valuation(c,ZZ(uniformizer(nu)))) +end +function (nu::TropicalSemiringMap{QQField,ZZRingElem,typeof(max)})(c::Union{RingElem,Integer,Rational}) + c = valued_field(nu)(c) + iszero(c) && return zero(tropical_semiring(nu)) # if input is zero, return tropical zero + return tropical_semiring(nu)(-valuation(c,ZZ(uniformizer(nu)))) +end + +# valued ring: +function valued_ring(nu::TropicalSemiringMap{QQField,ZZRingElem,minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return ZZ +end + +# residue field: +function residue_field(nu::TropicalSemiringMap{QQField,ZZRingElem,minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return GF(Int(uniformizer(nu))) +end + +# initial: +function initial(c::Union{RingElem,Integer,Rational}, nu::TropicalSemiringMap{QQField,ZZRingElem,minOrMax}) where {minOrMax<:Union{typeof(min),typeof(max)}} + c = valued_field(nu)(c) + iszero(c) && return zero(residue_field(nu)) # if c is zero, return 0 + c *= QQ(uniformizer(nu))^(-valuation(c,ZZ(uniformizer(nu)))) + return residue_field(nu)(c) +end + + + +################################################################################ +# +# t-adic valuation on K(t) +# +################################################################################ + +# Constructor: +@doc raw""" + tropical_semiring_map(Kt::Generic.RationalFunctionField, t::Generic.RationalFunctionFieldElem, minOrMax::Union{typeof(min),typeof(max)}=min) + +Return a map `nu` from rational function field `Kt` to the min (default) or max tropical semiring `T` such that `nu(0)=zero(T)` and `nu(c)=+/-val(c)` for `c` non-zero, where `val` denotes the `t`-adic valuation with uniformizer `t`. Requires `t` to be non-constant and have denominator `1`. + +# Example +```jldoctest +julia> Kt,t = rational_function_field(QQ,"t"); + +julia> nu_t = tropical_semiring_map(Kt,t) +Map into Min tropical semiring encoding the t-adic valuation on Rational function field over QQ + +julia> nu_t(t^2) +(2) + +julia> nu_t(1//t^2) +(-2) + +julia> nu_t = tropical_semiring_map(Kt,t,max) +Map into Max tropical semiring encoding the t-adic valuation on Rational function field over QQ + +julia> nu_t(t^2) +(-2) + +julia> nu_t(1//t^2) +(2) + +``` +""" +function tropical_semiring_map(Kt::Generic.RationalFunctionField, t::Generic.RationalFunctionFieldElem, minOrMax::Union{typeof(min),typeof(max)}=min) + @req isone(denominator(t)) "input uniformizer denominator not 1" + t = numerator(t) + @req degree(t)>0 "input uniformizer constant" + return TropicalSemiringMap{typeof(Kt),typeof(t),typeof(minOrMax)}(Kt,t,tropical_semiring(minOrMax)) +end + +# Display: +function Base.show(io::IO, nu::TropicalSemiringMap{Kt,t,minOrMax}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem, minOrMax<:Union{typeof(min),typeof(max)}} + print(io, "Map into $(tropical_semiring(nu)) encoding the $(uniformizer(nu))-adic valuation on $(valued_field(nu))") +end + +# Evaluation: +function t_adic_valuation(c::Generic.RationalFunctionFieldElem, t::PolyRingElem) + c_num = numerator(c) + c_nom = denominator(c) + return valuation(c_num,t)-valuation(c_nom,t) +end + +function (nu::TropicalSemiringMap{Kt,t,typeof(min)})(c::Union{RingElem,Integer,Rational}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem} + c = valued_field(nu)(c) + iszero(c) && return zero(tropical_semiring(nu)) # if c zero, return tropical zero + return tropical_semiring(nu)(t_adic_valuation(c,uniformizer(nu))) +end + +function (nu::TropicalSemiringMap{Kt,t,typeof(max)})(c::Union{RingElem,Integer,Rational}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem} + c = valued_field(nu)(c) + iszero(c) && return zero(tropical_semiring(nu)) # if c zero, return tropical zero + return tropical_semiring(nu)(-t_adic_valuation(c,uniformizer(nu))) +end + +# valued ring: +function valued_ring(nu::TropicalSemiringMap{Kt,t,minOrMax}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem, minOrMax<:Union{typeof(min),typeof(max)}} + return polynomial_ring(base_ring(valued_field(nu)),symbols(valued_field(nu)))[1] +end + +# residue field: +function residue_field(nu::TropicalSemiringMap{Kt,t,minOrMax}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem, minOrMax<:Union{typeof(min),typeof(max)}} + return base_ring(valued_field(nu)) +end + +# initial: +function initial(c::Union{RingElem,Integer,Rational}, nu::TropicalSemiringMap{Kt,t,minOrMax}) where {Kt<:Generic.RationalFunctionField, t<:PolyRingElem, minOrMax<:Union{typeof(min),typeof(max)}} + c = valued_field(nu)(c) + iszero(c) && return zero(residue_field(nu)) # if c is zero, return 0 + c *= valued_field(nu)(uniformizer(nu))^(-t_adic_valuation(c,uniformizer(nu))) + return residue_field(nu)(c) +end diff --git a/src/TropicalGeometry/tst.jl b/src/TropicalGeometry/tst.jl deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/src/TropicalGeometry/valuation.jl b/src/TropicalGeometry/valuation.jl deleted file mode 100644 index 4b0f93c6d6d6..000000000000 --- a/src/TropicalGeometry/valuation.jl +++ /dev/null @@ -1,464 +0,0 @@ -### -# Valuations over exact fields for tropical geometry -# ================================================== -### - -@doc raw""" - TropicalSemiringMap(K,p,M::Union{typeof(min),typeof(max)}=min) - -Constructs a map `val` from `K` to the min tropical semiring `T` (default) -or the max tropical semiring that: -- is a semigroup homomorphism `(K,*) -> (T,+)`, -- preserves the ordering on both sides. - -In other words, `val` is either a valuation on `K` with image in -`TropicalSemiring(min)` or the negative of a valuation on `K` with image in -`TropicalSemiring(max)`. - -The role of `val` is to encode with respect to which valuation on `K` and -under which convention (min or max) tropical computations should take place. - -Currently, the only supported valuations are: -- the $t$-adic valuation on $\mathbb{Q}(t)$ -- the $p$-adic valuations on $\mathbb{Q}$ -- the trivial valuation on any field - -# Examples - - $p$-adic valuation on $\mathbb{Q}$: -```jldoctest -julia> val_2 = TropicalSemiringMap(QQ,2); # = TropicalSemiringMap(QQ,2,min) - -julia> val_2(4) -(2) -julia> val_2(1//4) -(-2) -julia> val_2 = TropicalSemiringMap(QQ,2,max); - -julia> val_2(4) -(-2) -julia> val_2(1//4) -(2) -``` - - $t$-adic valuation on $\mathbb{Q}(t)$: -```jldoctest -julia> Kt,t = rational_function_field(QQ,"t"); - -julia> val_t = TropicalSemiringMap(Kt,t); - -julia> val_t(t^2) -(2) -julia> val_t(1//t^2) -(-2) -``` - -Trivial valuation on $\mathbb{Q}$: -```jldoctest -julia> val = TropicalSemiringMap(QQ); - -julia> val(4) -(0) -julia> val(1//4) -(0) -julia> val(0) -∞ -``` -""" -struct TropicalSemiringMap{typeofValuedField,typeofUniformizer} - valued_field::typeofValuedField - uniformizer_field::typeofUniformizer - valued_ring - uniformizer_ring - residue_field - residue_map - uniformizer_symbol - TropicalSemiring -end - - -################################################################################ -# -# Basic access -# -################################################################################ - -valued_field(val::TropicalSemiringMap) = val.valued_field -uniformizer_field(val::TropicalSemiringMap) = val.uniformizer_field -valued_ring(val::TropicalSemiringMap) = val.valued_ring -uniformizer_ring(val::TropicalSemiringMap) = val.uniformizer_ring -residue_field(val::TropicalSemiringMap) = val.residue_field -residue_map(val::TropicalSemiringMap) = val.residue_map -uniformizer_symbol(val::TropicalSemiringMap) = val.uniformizer_symbol -TropicalSemiring(val::TropicalSemiringMap) = val.TropicalSemiring -convention(val::TropicalSemiringMap) = convention(val.TropicalSemiring) - -### -# trivial valuation -### - -# Constructor: -function TropicalSemiringMap(K,M::Union{typeof(min),typeof(max)}=min) - residue_map(c) = return c - return TropicalSemiringMap{typeof(K),Nothing}(K,nothing,K,nothing,K,residue_map,nothing,TropicalSemiring(M)) -end - -# Evaluation: -function (val::TropicalSemiringMap{K,Nothing} where {K})(c) - if iszero(c) - return inf(val.TropicalSemiring) - end - return val.TropicalSemiring(0) -end - -# Display: -function Base.show(io::IO, val::TropicalSemiringMap{K,Nothing} where {K}) - print(io, "The trivial valuation on $(val.valued_field)") -end - - -### -# p-adic valuation on QQ -### - -# Constructor: -function TropicalSemiringMap(Q::QQField, p::QQFieldElem, M::Union{typeof(min),typeof(max)}=min) - function residue_map(c) - return finite_field(ZZ(p))[1](ZZ(c)) - end - return TropicalSemiringMap{typeof(Q),typeof(p)}(Q,p,ZZ,ZZ(p),finite_field(ZZ(p))[1],residue_map,:p,TropicalSemiring(M)) -end -# for other types of `p` such as `Integer` -TropicalSemiringMap(Q::QQField,p::ZZRingElem,M::Union{typeof(min),typeof(max)}=min) = TropicalSemiringMap(Q,QQ(p),M) -TropicalSemiringMap(Q::QQField,p::Int64,M::Union{typeof(min),typeof(max)}=min) = TropicalSemiringMap(Q,QQ(p),M) - -# Evaluation: -function (val::TropicalSemiringMap{QQField,QQFieldElem})(c) - if iszero(c) - return inf(val.TropicalSemiring) - end - if convention(val)==min - return val.TropicalSemiring(valuation(QQ(c),val.uniformizer_ring)) - end - return val.TropicalSemiring(-valuation(QQ(c),val.uniformizer_ring)) -end - -# Display: -function Base.show(io::IO, val::TropicalSemiringMap{QQField,QQFieldElem}) - print(io, "The $(val.uniformizer_field)-adic valuation on $(val.valued_field)") -end - - -### -# Laurent valuation on K(t) -### - -# t-adic valuation for elements in the valued field (=rational functions): -function t_adic_valuation(c::Generic.RationalFunctionFieldElem) - num = numerator(c) - nom = denominator(c) - return t_adic_valuation(num)-t_adic_valuation(nom) -end -# t-adic valuation for elements in the valued ring (=polynomials): -function t_adic_valuation(c::PolyRingElem) - return first(i for i in 0:degree(c) if !iszero(coeff(c, i))) -end - -# Constructor: -function TropicalSemiringMap(Kt::AbstractAlgebra.Generic.RationalFunctionField,t::AbstractAlgebra.Generic.RationalFunctionFieldElem,M::Union{typeof(min),typeof(max)}=min) - function residue_map(c) - valc = t_adic_valuation(c) - if (valc<0) - error("residue_map: input has negative valuation, not in valuation ring") - end - return base_ring(Kt)(evaluate(c,0)) - end - Rt,_ = polynomial_ring(base_ring(Kt),symbols(Kt)) - return TropicalSemiringMap{typeof(Kt),typeof(t)}(Kt,t,Rt,Rt(t),base_ring(Kt),residue_map,:t,TropicalSemiring(M)) -end - -# Evaluation: - -function (val::TropicalSemiringMap{S, T})(c) where {K, - S <: AbstractAlgebra.Generic.RationalFunctionField{K}, - T <: AbstractAlgebra.Generic.RationalFunctionFieldElem{K}} - if iszero(c) - return inf(val.TropicalSemiring) - end - if convention(val)==min - return val.TropicalSemiring(t_adic_valuation(c)) - end - return val.TropicalSemiring(-t_adic_valuation(c)) -end -# Display: -function Base.show(io::IO, val::TropicalSemiringMap{S, T}) where {K, - S <: AbstractAlgebra.Generic.RationalFunctionField{K}, - T <: AbstractAlgebra.Generic.RationalFunctionFieldElem{K}} - print(io, "The $(val.uniformizer_field)-adic valuation on $(val.valued_field)") -end - - - -### -# Check whether valuation is p-adic (as in: p-adic numbers), t-adic (as in: function fields), or trivial -# ====================================================================================================== -### - -function is_valuation_p_adic(val::TropicalSemiringMap) - return val.valued_field isa QQField && val.uniformizer_field isa QQFieldElem -end - -function is_valuation_t_adic(val::TropicalSemiringMap) - return val.valued_field isa AbstractAlgebra.Generic.RationalFunctionField && val.uniformizer_field isa AbstractAlgebra.Generic.RationalFunctionFieldElem -end - -function is_valuation_trivial(val::TropicalSemiringMap) - return typeof(val.uniformizer_field)==Nothing -end - -function is_valuation_nontrivial(val::TropicalSemiringMap) - return typeof(val.uniformizer_field)!=Nothing -end - - - -### -# Simulating valuations for algebraic computations in tropical geometry -# ===================================================================== -### - - - -### -# temporary workarounds: -### -function symbols(Kt::AbstractAlgebra.Generic.RationalFunctionField{K} where {K}) - return Kt.S -end - - - -#======= -functions which, given an ideal I in variables x1, ..., xn over a field with valuation, -returns an ideal vvI in variables t, x1, ..., xn such that tropical Groebner bases of I w.r.t. w -correspond to standard bases of I w.r.t. (-1,w) -Example: -K,s = rational_function_field(QQ,"s") -val_t = TropicalSemiringMap(K,s) -Kx,(x1,x2,x3) = polynomial_ring(K,3) -I = ideal([x1+s*x2,x2+s*x3]) -simulate_valuation(I,val_t) - -val_2 = TropicalSemiringMap(QQ,2) -Kx,(x,y,z) = polynomial_ring(QQ,3) -I = ideal([x+2*y,y+2*z]) -simulate_valuation(I,val_2) -=======# -function simulate_valuation(I::MPolyIdeal, val::TropicalSemiringMap) - return ideal(simulate_valuation(gens(I),val)) -end -function simulate_valuation(G::Vector{<:MPolyRingElem}, val::TropicalSemiringMap) - - # if the valuation is trivial, then nothing needs to be done - if is_valuation_trivial(val) - return G - end - if length(G)==0 - error("input vector of polynomials empty, thus ambient polynomial ring unknown") - end - - R = val.valued_ring - t = val.uniformizer_symbol - - Rtx,tx = polynomial_ring(R,vcat([t],symbols(parent(G[1])))) - vvG = [val.uniformizer_ring-tx[1]] - for f in G - fRtx = MPolyBuildCtx(Rtx) - for (cK,expvKx) = zip(AbstractAlgebra.coefficients(f),AbstractAlgebra.exponent_vectors(f)) - @assert isone(denominator(cK)) "change_base_ring: coefficient denominators need to be 1" - cR = R(numerator(cK)) # coefficient in R - expvRtx = vcat([0],expvKx) # exponent vector in R[t,x1,...,xn] - push_term!(fRtx,cR,expvRtx) - end - push!(vvG,tighten_simulation(finish(fRtx),val)) - end - - return vvG -end - -function simulate_valuation(w::Vector, val::TropicalSemiringMap) - # if the valuation is non-trivial, prepend -1 to the vector - if !is_valuation_trivial(val) - w = vcat([-1],w) - end - # either way, scale vector to make entries integral - commonDenom = lcm([denominator(wi) for wi in w]) - sw = [Int(numerator(commonDenom*wi)) for wi in w] # casting vector entries to Int32 for Singular - if convention(val)==min - sw *= -1 - end - return sw -end - -function simulate_valuation(w::Vector, u::Vector, val::TropicalSemiringMap) - # if the valuation is non-trivial, prepend -1 to the vector - if !is_valuation_trivial(val) - w = vcat([-1],w) - u = vcat([0],u) - end - # either way, scale vector to make entries integral - w_commonDenom = lcm([denominator(wi) for wi in w]) - u_commonDenom = lcm([denominator(ui) for ui in u]) - sw = [Int(numerator(w_commonDenom*wi)) for wi in w] - su = [Int(numerator(u_commonDenom*ui)) for ui in u] - if convention(val)==min - sw *= -1 - su *= -1 - end - return sw,su -end - -#======= -functions which, given an ideal I in variables x1, ..., xn over a field with valuation, -returns an ideal vvI in variables t, x1, ..., xn such that tropical Groebner bases of I w.r.t. w -correspond to standard bases of I w.r.t. (-1,w) -Example: -val_2 = TropicalSemiringMap(QQ,2) -Kx,(x,y,z) = polynomial_ring(QQ,3) -I = ideal([x+2*y,y+2*z]) -vvI = simulate_valuation(I,val_2) -desimulate_valuation(vvI,val_2) - -Ks,s = rational_function_field(QQ,"s") -val_s = TropicalSemiringMap(Ks,s) -Ksx,(x1,x2,x3) = polynomial_ring(Ks,3) -I = ideal([x1+s*x2,x2+s*x3]) -vvI = simulate_valuation(I,val_s) -desimulate_valuation(vvI,val_s) -=======# -function desimulate_valuation(vvI::MPolyIdeal,val::TropicalSemiringMap) - return ideal([g for g in desimulate_valuation(gens(vvI),val) if !iszero(g)]) -end - -function desimulate_valuation(vvG::Vector{<:MPolyRingElem}, val::TropicalSemiringMap) - return [desimulate_valuation(vvg,val) for vvg in vvG] -end - -function desimulate_valuation(vvg::MPolyRingElem, val::TropicalSemiringMap) - Rx = parent(vvg) - R = coefficient_ring(Rx) - x = copy(symbols(Rx)) - popfirst!(x) - - K = val.valued_field - Kx,_ = polynomial_ring(K,x) - - vvg = evaluate(vvg,[1],[val.uniformizer_ring]) - if iszero(vvg) # vvg may be p-t - return Kx(0) - end - - g = MPolyBuildCtx(Kx) - for (c, expvRtx) = Base.Iterators.zip(AbstractAlgebra.coefficients(vvg), AbstractAlgebra.exponent_vectors(vvg)) - expvKx = copy(expvRtx) # exponent vector in R[t,x1,...,xn] - popfirst!(expvKx) # exponent vector in K[x1,...,xn] - push_term!(g,K(c),expvKx) - end - return finish(g) -end - -function desimulate_valuation(w::Vector,val::TropicalSemiringMap) - # if the valuation is non-trivial, scale the vector so that first entry is -1 - # and then remove first entry - if !is_valuation_trivial(val) - w /= w[1] - popfirst!(w) - end - if convention(val)==min - w *= -1 - end - return w -end - -function desimulate_valuation(w::Vector, u::Vector, val::TropicalSemiringMap) - # if the valuation is non-trivial, scale the vector w so that first entry is -1 - # and then remove first entry of both w and u - if !is_valuation_trivial(val) - w /= w[1] - popfirst!(w) - popfirst!(u) - end - if convention(val)==min - w *= -1 - u *= -1 - end - return w,u -end - - -#======= -Given a polynomial f in t,x_1, ..., x_n simulating the valuation: -- If f==p-t or f==t-p, returns f -- Otherwise, returns a polynomial f' in such that - * f' and f share the same monomials in x - * all terms of f' have distinct monomials in x - * all terms of f' have valuation 0 coefficients -Example: -val_2 = TropicalSemiringMap(QQ,2) -Rtx,(p,x1,x2,x3) = polynomial_ring(val_2.valued_ring,["p","x1","x2","x3"]) -f = x1+p*x1+p^2*x1+2^2*x2+p*x2+p^2*x2+x3 -tighten_simulation(f,val_2) -tighten_simulation(2^3*f,val_2) -tighten_simulation(p^3*f,val_2) - -K,s = rational_function_field(QQ,"s") -val_s = TropicalSemiringMap(K,s) -s = val_s.uniformizer_ring -Rtx,(t,x1,x2,x3) = polynomial_ring(val_s.valued_ring,["t","x1","x2","x3"]) -f = x1+t*x1+t^2*x1+s^2*x2+t*x2+t^2*x2+x3 -tighten_simulation(f,val_s) -tighten_simulation(s^3*f,val_s) -tighten_simulation(t^3*f,val_s) -=======# -function tighten_simulation(f::MPolyRingElem,val::TropicalSemiringMap) - @assert !iszero(f) - # return f if f = p-t or t-p - Rtx = parent(f) - p = val.uniformizer_ring - pt = p - gen(Rtx, 1) - if f==pt || f==-pt - return f - end - - # substitute first variable by uniformizer_ring so that all monomials have distinct x-monomials - # and compute the gcd of its coefficients - f = evaluate(f,[1],[p]) # todo: sanity check that f is not 0 - cGcd = val.valued_field(gcd([c for c in AbstractAlgebra.coefficients(f)])) - - # next divide f by the gcd of its coefficients - # and replace uniformizer_ring by first variable - K = val.valued_field - R = val.valued_ring - p = val.uniformizer_field - f_tightened = MPolyBuildCtx(Rtx) - for (c,alpha) in zip(AbstractAlgebra.coefficients(f),AbstractAlgebra.exponent_vectors(f)) - c = K(c)//cGcd # casting c into K for the t-adic valuation case where typeof(c)=QQPolyRingElem - v = Int(val(c); preserve_ordering=true) - alpha[1] += v - push_term!(f_tightened,R(c//p^v),alpha) - end - - return finish(f_tightened) - -end - - -# function valuation_Int(val::TropicalSemiringMap, c) -# assert !iszero(c) -# vc = Int(ZZ(data(val(c)))) -# if convention(valuation)==min -# return vc -# else -# return -vc -# end -# end diff --git a/src/TropicalGeometry/variety.jl b/src/TropicalGeometry/variety.jl index 2af2c93a8cd9..cda4a4eadbd6 100644 --- a/src/TropicalGeometry/variety.jl +++ b/src/TropicalGeometry/variety.jl @@ -1,390 +1,776 @@ -### -# Tropical varieties in Oscar -# =========================== -### +################################################################################ +# +# Tropical varieties +# ================== +# concrete subtype of TropicalVarietySupertype in variety_supertype.jl +# +################################################################################ +@attributes mutable struct TropicalVariety{minOrMax,isEmbedded} <: TropicalVarietySupertype{minOrMax,isEmbedded} + polyhedralComplex::PolyhedralComplex + multiplicities::Vector{ZZRingElem} + # tropical varieties need to be embedded + function TropicalVariety{minOrMax,true}(Sigma::PolyhedralComplex,multiplicities::Vector{ZZRingElem}) where {minOrMax<:Union{typeof(min),typeof(max)}} + return new{minOrMax,true}(Sigma,multiplicities) + end +end -### -# 0. Definition -# ------------- -# M = typeof(min) or typeof(max): -# min or max convention, affecting initial ideals -# EMB = true or false: -# embedded or abstract tropical variety -# embedded tropical variety = weighted polyhedral complex in euclidean space -# abstract tropical variety = weighted hypergraph with enumerated vertices -### -@attributes mutable struct TropicalVariety{M,EMB} <: TropicalVarietySupertype{M,EMB} - polyhedralComplex::PolyhedralComplex - multiplicities::Dict{Vector{Int}, Int} - function TropicalVariety{M,EMB}(Sigma::PolyhedralComplex) where {M,EMB} - return new{M,EMB}(Sigma) - end + +################################################################################ +# +# Printing +# +################################################################################ + +function Base.show(io::IO, tv::TropicalVariety{typeof(min), true}) + print(io, "Min tropical variety") +end +function Base.show(io::IO, tv::TropicalVariety{typeof(max), true}) + print(io, "Max tropical variety") end -function pm_object(T::TropicalVariety) - if has_attribute(T,:polymake_bigobject) - return get_attribute(T,:polymake_bigobject) - end - error("pm_object(T::TropicalVariety): Has no polymake bigobject.") + +################################################################################ +# +# Constructors +# +################################################################################ + +@doc raw""" + tropical_variety(Sigma::PolyhedralComplex, mult, minOrMax::Union{typeof(min),typeof(max)}=min) + +Return the `TropicalVariety` whose polyhedral complex is `Sigma` with multiplicities `mult` and convention `minOrMax`. Here, `mult` is optional can be specified as a `Vector{ZZRingElem}` which represents a list of multiplicities on the maximal polyhedra in the order of `maximal_polyhedra(Sigma)`. If `mult` is unspecified, then all multiplicities are set to one. + +# Examples +```jldoctest +julia> Sigma = polyhedral_complex(IncidenceMatrix([[1],[2]]), [[0],[1]]) +Polyhedral complex in ambient dimension 1 + +julia> tropical_variety(Sigma) +Min tropical variety + +julia> mult = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) +2-element Vector{ZZRingElem}: + 1 + 1 + +julia> tropical_variety(Sigma,mult,min) +Min tropical variety + +julia> mult = ZZ.([1,2]) +2-element Vector{ZZRingElem}: + 1 + 2 + +julia> tropical_variety(Sigma,mult,max) +Max tropical variety + +``` +""" +function tropical_variety(Sigma::PolyhedralComplex, mult::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return TropicalVariety{typeof(minOrMax),true}(Sigma,mult) +end +function tropical_variety(Sigma::PolyhedralComplex, minOrMax::Union{typeof(min),typeof(max)}=min) + mult = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) + return tropical_variety(Sigma,mult,minOrMax) end +function tropical_variety(TropH::TropicalHypersurface{minOrMax,true}) where {minOrMax<:Union{typeof(min),typeof(max)}} + TropV = tropical_variety(polyhedral_complex(TropH),multiplicities(TropH), convention(TropH)) + if has_attribute(TropH,:algebraic_polynomial) + set_attribute!(TropV,:algebraic_ideal,ideal([get_attribute(TropH,:algebraic_polynomial)])) + end + if has_attribute(TropH,:tropical_semiring_map) + set_attribute!(TropV,:tropical_semiring_map,get_attribute(TropH,:tropical_semiring_map)) + end -### -# 1. Printing -# ----------- -### + return TropV +end -function Base.show(io::IO, tv::TropicalVariety{M, EMB}) where {M, EMB} - if EMB - print(io, "$(repr(M)) tropical variety of dimension $(dim(tv)) embedded in $(ambient_dim(tv))-dimensional Euclidean space") - else - print(io, "Abstract $(repr(M)) tropical variety of dimension $(dim(tv))") + +function tropical_variety(TropL::TropicalLinearSpace{minOrMax,true}) where {minOrMax<:Union{typeof(min),typeof(max)}} + TropV = tropical_variety(polyhedral_complex(TropL),multiplicities(TropL), convention(TropL)) + + if has_attribute(TropL,:algebraic_ideal) + set_attribute!(TropV,:algebraic_ideal,get_attribute(TropL,:algebraic_ideal)) + end + if has_attribute(TropL,:tropical_semiring_map) + set_attribute!(TropV,:tropical_semiring_map,get_attribute(TropL,:tropical_semiring_map)) end + + return TropV end -### -# 2. Basic constructors -# --------------------- -### +function tropical_variety(Sigma::Vector{<:Polyhedron}, multiplicities::Vector{ZZRingElem}, minOrMax::Union{typeof(min),typeof(max)}=min) + return tropical_variety(polyhedral_complex(Sigma; non_redundant=true),multiplicities,minOrMax) +end -@doc raw""" - TropicalVariety() -Construct the embedded tropical variety of a polynomial ideal over a (possibly trivially) valued field -# Examples -""" -# todo: Dartmouth -# function TropicalVariety() + +################################################################################ # -# return #... -# end +# Properties +# ---------- +# none, see variety_supertype.jl for common properties of all tropical variety types +# +################################################################################ +################################################################################ +# +# Tropical varieties of polynomial ideals +# ---------- +# References for computing tropical varieties via Groebner complex traversal: +# T. Bogart, A. Jensen, D. Speyer, B. Sturmfels, R. Thomas: Computing tropical varieties +# T. Markwig, Y. Ren: Computing tropical points over fields with valuation +# +################################################################################ + @doc raw""" - TropicalVariety{M,EMB}(Sigma::PolyhedralComplex) + tropical_variety(I::MPolyIdeal, nu::Union{TropicalSemiringMap,Nothing}=nothing; weighted_polyhedral_complex_only::Bool=false, skip_saturation::Bool=false, skip_primary_decomposition::Bool=false) + +Return the tropicalization of `I` with respect to `nu` as a `Vector{TropicalVariety}`. +If `nu==nothing`, will compute with respect to the trivial valuation and min convention. +If `weighted_polyhedral_complex_only==true`, will not cache any additional information. +If `skip_saturation==true`, will not saturate `I` with respect to the product of all variables. +If `skip_primary_decomposition==true`, will not decompose `I`. -Construct the abstract tropical variety from a polyhedral complex +!!! warning + `tropical_variety` is currently under development and only works for ideal that decompose into + primary ideals, linear ideals, and binomial ideals. # Examples ```jldoctest -julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]); - -julia> VR = [0 0; 1 0; 0 1; -1 -1]; +julia> R,(x,y) = QQ["x","y"]; -julia> far_vertices = [2,3,4]; +julia> I = ideal([(x^2+y)*(x+y^2)*(x+y)]); -julia> Sigma = polyhedral_complex(IM, VR, far_vertices); +julia> tropical_variety(I) +3-element Vector{TropicalVariety}: + Min tropical variety + Min tropical variety + Min tropical variety -julia> tropicalLine = TropicalVariety{min,true}(Sigma) +``` """ +function tropical_variety(I::Union{MPolyIdeal,MPolyRingElem}, nu::Union{TropicalSemiringMap,Nothing}=nothing; weighted_polyhedral_complex_only::Bool=false, skip_saturation::Bool=false, skip_primary_decomposition::Bool=false) + ### + # Step 0.a: convert I to ideal if poly, + # initialise nu as the trivial valuation if not specified by user + ### + if I isa MPolyRingElem + I = ideal(parent(I),[I]) + end + if isnothing(nu) + nu = tropical_semiring_map(coefficient_ring(I)) + end + ### + # Step 0.b: Saturate `I` and assert that `I` is not the whole ring + ### + if !skip_saturation + R = base_ring(I) + I = saturation(I,ideal([prod(gens(R))])) + end + @req !isone(I) "ideal contains a monomial, tropical varieties in OSCAR cannot be empty" + + ### + # Step 0.c: Compute primary decomposition and tropical varieties of all primary factors + ### + toTropicalize = [I] + if !skip_primary_decomposition + toTropicalize = [ P for (P,_) in primary_decomposition(I) ] + end -### -# 3. Basic properties -# ------------------- -### - + tropicalVarieties = TropicalVariety[] + for P in toTropicalize + # compute a reduced GB to test whether `P` is principal, binomial, or linear + GB = groebner_basis(P,complete_reduction=true) + + if length(GB)==1 + # P is principal + TropV = tropical_variety_principal(P,nu,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + elseif max(length.(GB)...)==2 + # P is binomial + TropV = tropical_variety_binomial(P,nu,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + elseif max(total_degree.(GB)...)==1 + # P linear + TropV = tropical_variety_linear(P,nu,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only) + else + # P general + error("general tropical varieties currently unsupported") + end + push!(tropicalVarieties,TropV) + end + return tropicalVarieties +end -### -# 4. Tropical varieties of polynomial ideals -# ------------------------------------------ -# References for computing tropical varieties via traversal: -# T. Bogart, A. Jensen, D. Speyer, B. Sturmfels, R. Thomas: Computing tropical varieties -# T. Markwig, Y. Ren: Computing tropical points over fields with valuation -# Reference for the general structure of tropical varieties: -# D. Maclagan, B. Sturmfels: Introduction to tropical geometry -### -function homogenize(I::MPolyIdeal) - G = groebner_basis(I,complete_reduction=true) - - Kx = base_ring(I) - K = coefficient_ring(Kx) - x = symbols(Kx) - Kxh,_ = polynomial_ring(K,vcat([:xh],x)) - - Gh = Vector{elem_type(Kx)}(undef,length(G)) - for (i,g) in enumerate(G) - gh = MPolyBuildCtx(Kxh) - d = max([sum(expv) for expv in AbstractAlgebra.exponent_vectors(g)]...) # degree of g ?? TODO isn't this just total_degree(g) ?? - for (c,alpha) in zip(AbstractAlgebra.coefficients(g), AbstractAlgebra.exponent_vectors(g)) - pushfirst!(alpha,d-sum(alpha)) # homogenize exponent vector - push_term!(gh,c,alpha) +################################################################################ +# +# Principal ideals +# +################################################################################ + +function tropical_variety_principal(I::MPolyIdeal,nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) + ### + # Construct TropicalVariety from TropicalHypersurface + ### + g = first(gens(I)) + TropV = tropical_variety(tropical_hypersurface(g,nu,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only)) + if !weighted_polyhedral_complex_only + set_attribute!(TropV,:algebraic_ideal,I) + set_attribute!(TropV,:tropical_semiring_map,nu) end - Gh[i] = finish(gh) - end - - return ideal(Gh) + return TropV end -#======= -tropical variety of an ideal -todo: proper documentation -Example: -import Random -K,s = rational_function_field(QQ,"s"); -Kx,(x1,x2,x3,x4) = polynomial_ring(K,4); -val = TropicalSemiringMap(K,s); -I = ideal([x1-s*x2+(s+1)*x3,3*x2-s^2*x3+(s^2+1)*x4]); -Random.seed!(3847598273423); -TropI = tropical_variety(I,val) -=======# -function tropical_variety(I::MPolyIdeal, val::TropicalSemiringMap, convention::Union{typeof(min),typeof(max)}=min) - - ### - # Part 0: Preprocessing - # Check whether valuation is on the coefficient ring of input polynomials, - # homogenize input ideal if not homogeneous - ### - if coefficient_ring(base_ring(I))!=val.valued_field - error("input valuation not on coefficient ring of input ideal") - end - was_input_homogeneous = true - for g in groebner_basis(I,complete_reduction=true) # todo: replace GB computation with interreduction - if !sloppy_is_homogeneous(g) - was_input_homogeneous = false - I = homogenize(I) - break - end - end - - - - ### - # Part 1: Tropical starting polyhedra (todo: avoid recomputation) - # - compute and recompute starting points until they lie in the relative interior of maximal cells - # - initialize working lists - ### - - # Note: a working list entry consists of a triple (w,C,G) where - # * G is a (tropical) Groebner basis - # * C is the Groebner polyhedron - # * w is the sum of vertices and rays of C - # In particular: - # * w is a weight vector with respect to which G is a Groebner basis, - # * w is compatible with coordinate permutations if symmetries exist, - # * instead of comparing C or G it suffices to compare w. - working_list_todo = [] # list of groebner polyhedra with potentially unknown neighbours - working_list_done = [] # list of groebner polyhedra with known neighbours - facet_points_done = [] # list of facet points whose tropical links were computed and traversed - - compute_starting_points = true - while compute_starting_points - print("computing random starting points... ") - starting_points = tropical_points(I,val) - println("done") - - working_list_todo = [] - working_list_done = [] - facet_points_done = [] - compute_starting_points = false - for starting_point in starting_points - print("computing groebner_basis for starting point ",starting_point,"... ") - G = groebner_basis(I,val,starting_point) - println("done") - C = groebner_polyhedron(G,val,starting_point) - w = anchor_point(C) - - # if C is lower-dimensional, recompute all starting points - if dim(C)!=dim(I) - println("starting point on lower-dimensional cell, recomputing...") - compute_starting_points = true - break - end - - # if (w,C,G) already is in working_list_todo, skip - i = searchsortedfirst(working_list_todo,(w,C,G),by=x->x[1]) - if i<=length(working_list_todo) && working_list_todo[i][1]==w - continue - end - # otherwise, add (w,C,G) to todo list - insert!(working_list_todo, i, (w,C,G)) + +################################################################################ +# +# Binomial ideals +# +################################################################################ + +function tropical_variety_binomial(I::MPolyIdeal,nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) + ### + # Compute reduced Groebner basis (usually already cached), + # construct matrix of exponent vector differences + # and vector of coefficient valuation differences + ### + G = groebner_basis(I,complete_reduction=true) + A = matrix(ZZ,[first(collect(expv))-last(collect(expv)) for expv in exponents.(G)]) + b = [ QQ(nu(last(collect(coeff))/first(collect(coeff)))) for coeff in coefficients.(G)] + + ### + # Compute tropical variety multiplicity + ### + @req ncols(A)>nrows(A) "input needs to be a GB" + weight = abs(prod([snf(A)[i,i] for i in 1:nrows(A)])) + + ### + # Constructing tropical variety set-theoretically + ### + A = QQMatrix(A) + L = matrix(QQ,kernel_basis(A)) + can_solve, V = can_solve_with_solution(transpose(A),matrix(QQ,[b]),side=:left) + @req can_solve "tropical variety cannot be empty" + SigmaV = polyhedral_complex(IncidenceMatrix([[1]]), V, nothing, L) + + ### + # Assemble tropical variety + ### + TropV = tropical_variety(SigmaV,[weight],convention(nu)) + if !weighted_polyhedral_complex_only + set_attribute!(TropV,:algebraic_ideal,I) + set_attribute!(TropV,:tropical_semiring_map,nu) end - end - - - - ### - # Part 2: Tropical traversal - ### - while !isempty(working_list_todo) - print("#working_list_todo: ",length(working_list_todo)," ") - println("#working_list_done: ",length(working_list_done)) - - # pick a groebner polyhedron from todo list, add it to the done list, and compute its facet points - (w,C,G) = popfirst!(working_list_todo) - i = searchsortedfirst(working_list_done,(w,C,G),by=x->x[1]) - insert!(working_list_done, i, (w,C,G)) - - points_to_traverse = facet_points(C) - for point_to_traverse in points_to_traverse - # if point was traversed before, skip - i = searchsortedfirst(facet_points_done,point_to_traverse) - if i<=length(facet_points_done) && facet_points_done[i]==point_to_traverse - continue - end - # otherwise add point_to_traverse to facet_points_done - insert!(facet_points_done, i, point_to_traverse) - - directions_to_traverse = tropical_link(ideal(G),val,point_to_traverse) # todo, this output can be wrong - for direction_to_traverse in directions_to_traverse - # compute neighbour - print("computing groebner_basis for ",point_to_traverse,direction_to_traverse,"... ") - G_neighbour = groebner_flip(G,val,w,point_to_traverse,direction_to_traverse) - println("done") - C_neighbour = groebner_polyhedron(G_neighbour,val,point_to_traverse,perturbation=direction_to_traverse) - w_neighbour = anchor_point(C_neighbour) - - # if neighbour is already in done list, skip - i = searchsortedfirst(working_list_done, - (w_neighbour,C_neighbour,G_neighbour), - by=x->x[1]) - if i<=length(working_list_done) && working_list_done[i][1]==w_neighbour - continue + return TropV +end + + + +################################################################################ +# +# Linear ideals +# +################################################################################ + +function tropical_variety_linear(I::MPolyIdeal,nu::TropicalSemiringMap; weighted_polyhedral_complex_only::Bool=false) + ### + # Compute reduced Groebner basis (usually already cached), + # and check whether the linear polynomials have a constant term + ### + R = base_ring(I) + G = groebner_basis(I,complete_reduction=true) + if min(total_degree.(Iterators.flatten(collect.(terms.(G))))...)==1 + # input homogneeous, construct TropicalVariety via TropicalLinearSpace + TropV = tropical_variety(tropical_linear_space(I,nu,weighted_polyhedral_complex_only=weighted_polyhedral_complex_only)) + if !weighted_polyhedral_complex_only + set_attribute!(TropV,:algebraic_ideal,I) + set_attribute!(TropV,:tropical_semiring_map,nu) end - # if neighbour is already in todo list, skip - i = searchsortedfirst(working_list_todo, - (w_neighbour,C_neighbour,G_neighbour), - by=x->x[1]) - if i<=length(working_list_todo) && working_list_todo[i][1]==w_neighbour - continue + return TropV + else + # input inhomogeneous, homogenise first + Ih = homogenize_pre_tropicalization(I) + TropLh = tropical_linear_space(Ih,nu,weighted_polyhedral_complex_only=true) + Sigma = dehomogenize_post_tropicalization(polyhedral_complex(TropLh)) + + multiplicities = ones(ZZRingElem, n_maximal_polyhedra(Sigma)) + TropV = tropical_variety(Sigma,multiplicities) + if !weighted_polyhedral_complex_only + set_attribute!(TropV,:algebraic_ideal,I) + set_attribute!(TropV,:tropical_semiring_map,nu) end - # otherwise, add neighbour to todo list - insert!(working_list_todo, i, (w_neighbour,C_neighbour,G_neighbour)) - end + return TropV end - end +end +function homogenize_pre_tropicalization(I::MPolyIdeal) + ### + # Compute reduced Groebner basis (usually already cached), and construct homogenization + ### + G = groebner_basis(I,complete_reduction=true) + + Kx = base_ring(I) + K = coefficient_ring(Kx) + x = symbols(Kx) + Kxhx,_ = polynomial_ring(K,vcat([:xh],x)) + + Gh = Vector{elem_type(Kx)}(undef,length(G)) + for (i,g) in enumerate(G) + gh = MPolyBuildCtx(Kxhx) + d = total_degree(g) + for (c,alpha) in coefficients_and_exponents(g) + pushfirst!(alpha,d-sum(alpha)) # homogenize exponent vector + push_term!(gh,c,alpha) + end + Gh[i] = finish(gh) + end - ### - # Part 3: Postprocessing - ### - # 3.0: dehomogenize data if input was homogenized - if !was_input_homogeneous - n = length(gens(base_ring(I))) + return ideal(Gh) +end - # 3.0.1: dehomogenize Groebner polyhedra - zeroth_unit_vector_as_row_vector = zeros(Int,1,n) - zeroth_unit_vector_as_row_vector[1,1] = 1 - dehomogenising_hyperplane = polyhedron((zeros(Int,0,n),zeros(Int,0)), - (zeroth_unit_vector_as_row_vector,[1])) - for wCG in working_list_done - wCG[2] = intersect(wCG[2],dehomogenising_hyperplane) - end - # 3.0.2: check that initial ideals are distinct (todo) - end - - # 3.1: construct PolyhedralComplex - # 3.1.1: construct incidence_matrix, vertices_and_rays, and far_vertices - incidence_matrix = Vector{Vector{Int}}() - verts_rays = Vector{Vector{Polymake.Rational}}() - far_vertices = Vector{Int}() - for (w,C,G) in working_list_done - incidence_vector = Vector{Int}() - for vert in vertices(C) - i = findfirst(isequal(vert),verts_rays) - if i === nothing - # if vert does not occur in verts_rays - # add it to verts_rays - push!(verts_rays,vert) - push!(incidence_vector,length(verts_rays)) - else - push!(incidence_vector,i) - end - end - for ray in rays(C) - i = findfirst(isequal(ray),verts_rays) - if i === nothing || !(i in far_vertices) - # if ray does not occur in verts_rays or if it occurs but not as a ray, - # add it to verts_rays - push!(verts_rays,ray) - push!(far_vertices,length(verts_rays)) - push!(incidence_vector,length(verts_rays)) - else - push!(incidence_vector,i) - end + +function dehomogenize_post_tropicalization(Sigma::PolyhedralComplex) + @req lineality_dim(Sigma)>0 "dehomogenizing polyhedral complex without lineality" + + ### + # Construct hyperplane {first coord = 0} + ### + n = ambient_dim(Sigma) + zerothUnitRowVector = zeros(Int,1,n) + zerothUnitRowVector[1,1] = 1 + dehomogenisingHyperplane = polyhedron((zeros(Int,0,n),zeros(Int,0)), (zerothUnitRowVector,[0])) + + ### + # Construct matrix and incidence matrix of vertices and rays + ### + incidenceMatrixVertices = Vector{Int}[] + dehomogenizedVertices = Vector{QQFieldElem}[] + incidenceMatrixRays = Vector{Int}[] + dehomogenizedRays = Vector{QQFieldElem}[] + for sigma in maximal_polyhedra(Sigma) + sigmaDehomogenized = intersect(sigma,dehomogenisingHyperplane) + incidenceVectorVertices = Int[] + V,_ = minimal_faces(sigmaDehomogenized) + for vertex in V + vertex = vertex[2:end] + i = findfirst(isequal(vertex),dehomogenizedVertices) + if i === nothing + push!(dehomogenizedVertices,vertex) + push!(incidenceVectorVertices,length(dehomogenizedVertices)) + else + push!(incidenceVectorVertices,i) + end + end + push!(incidenceMatrixVertices,incidenceVectorVertices) + + incidenceVectorRays = Int[] + R,_ = rays_modulo_lineality(sigmaDehomogenized) + for ray in R + ray = ray[2:end] + i = findfirst(isequal(ray),dehomogenizedRays) + if i === nothing + push!(dehomogenizedRays,ray) + push!(incidenceVectorRays,length(dehomogenizedRays)) + else + push!(incidenceVectorRays,i) + end + end + push!(incidenceMatrixRays,incidenceVectorRays) end - push!(incidence_matrix,incidence_vector) - end - verts_rays_matrix = permutedims(reduce(hcat, verts_rays)) # convert Vector{Vector} to Matrix + ### + # Concatenate vertically matrixes of vertices and rays, + # shift incidence matrix of rays and concatenate it horizontally to incicende matrix of vertices, + # dehomogenize generators of lineality space + ### + dehomogenizedVerticesAndRays = matrix(QQ,vcat(dehomogenizedVertices,dehomogenizedRays)) + incidenceMatrixRaysShifted = (x -> x .+length(dehomogenizedVertices)).(incidenceMatrixRays) + incidenceMatrixVerticesAndRays = IncidenceMatrix([vcat(iv,ir) for (iv,ir) in zip(incidenceMatrixVertices,incidenceMatrixRaysShifted)]) + + ### + # Dehomogenize lineality space + ### + sigma = first(maximal_polyhedra(Sigma)) + sigmaDehomogenized = intersect(sigma,dehomogenisingHyperplane) + dehomogenizedLineality = [linealityVector[2:end] for linealityVector in lineality_space(sigmaDehomogenized)] + + return polyhedral_complex(incidenceMatrixVerticesAndRays, + dehomogenizedVerticesAndRays, + collect(length(dehomogenizedVertices)+1:length(dehomogenizedVertices)+length(dehomogenizedRays)), + dehomogenizedLineality) +end - # 3.1.2: construct lineality space - (w,C,G) = first(working_list_done) - lineality_space_gens = matrix(QQ,lineality_space(C)) +################################################################################ +# +# Zero-dimensional ideals +# +################################################################################ + +function tropical_variety_zerodimensional(I::MPolyIdeal,nu::TropicalSemiringMap{QQField,QQFieldElem,<:Union{typeof(min),typeof(max)}}) + + k,(a,_) = number_field(I) + zk = maximal_order(k) + p = uniformizer(nu) + lp = [x[1] for x = prime_decomposition(zk,p)] + ma = representation_matrix(a) + mb = representation_matrix(k(lp[1].gen_two*lp[2].gen_two^2)) + @assert iszero(ma*mb - mb*ma) + Qp = PadicField(p, 10) + TropVDict = simultaneous_diagonalization([map_entries(Qp, ma),map_entries(Qp, mb)]) + + TropVPoints = collect(values(TropVDict)) + TropVPointsUnique = unique(TropVPointsMults) + Sigma = polyhedral_complex(IncidenceMatrix([[i] for i in 1:length(TropVPointsUnique)]), TropVPointsUnique) + TropVMults = [ZZ(length(findall(isequal(p),TropVPoints))) for p in TropVPointsUnique] + TropV = tropical_variety(Sigma,TropVMults) + set_attribute!(TropV,:algebraic_points,collect(keys(TropVDict))) + return TropV +end - # 3.2: Construct lists for weight_vectors, initial_ideals and multiplicities - weight_vectors = [w for (w,C,G) in working_list_done] - initial_ideals = [ideal(initial(G,val,w)) for (w,C,G) in working_list_done] - multiplicities = [multiplicity(inI) for inI in initial_ideals] +### +# Code by Claus: +### +function slope_eigenspace(M::MatElem{T}) where T <: Hecke.NonArchLocalFieldElem + f = charpoly(M) + lf = Hecke.slope_factorization(f) + # @req all(x->x==1, values(lf)) + se = Dict{typeof(f), typeof(M)}() + k = base_ring(M) + zk = maximal_order(k) - PC = polyhedral_complex(IncidenceMatrix(incidence_matrix), - verts_rays_matrix, - far_vertices, - lineality_space_gens) + for f = keys(lf) + se[f] = kernel(f(M))[2] #hopefully, this is in rref + end + @assert sum(ncols(x) for x = values(se)) == nrows(M) + return se +end - verts_rays_perm = collect(vertices_and_rays(PC)) - verts_rays_perm = Vector{Int64}.(verts_rays_perm) - permutation = [findfirst(isequal(l), verts_rays_perm) for l in verts_rays] -# inc = [findall(c -> c, incidence_matrix[i, :]) for i in 1:size(incidence_matrix, 1)] - new_incidence = [permutation[incidence] for incidence in incidence_matrix] - mults = Dict(new_incidence[i] => multiplicities[i] for i in 1:length(working_list_done)) +function _intersect(M::MatElem{T}, N::MatElem{T}) where T <: Hecke.FieldElem + k = base_ring(M) + I = [M N] + PR = maximum(precision, I) + pr = minimum(precision, I) + if pr != PR + for i = eachindex(I) + I[i] = setprecision(I[i], pr) + end + end - TropI = TropicalVariety{typeof(max),true}(PC, mults) + r, v = kernel(I) #precision issues... + l = M*v[1:ncols(M), 1:r] + return transpose(rref(transpose(l))[2]) +end +function valuation_of_roots(f::PolyElem{<:Hecke.NonArchLocalFieldElem}) + iszero(f) && error("polynomial must not be zero") + return (valuation(constant_coefficient(f)) - valuation(leading_coefficient(f)))//degree(f) +end - set_attribute!(TropI,:weight_vectors,weight_vectors) - set_attribute!(TropI,:initial_ideals,initial_ideals) +function simultaneous_diagonalization(v::Vector{<:MatElem{T}}) where T <: Hecke.NonArchLocalFieldElem + + k = base_ring(v[1]) + @assert all(x->base_ring(x) == k, v) + n = nrows(v[1]) + @assert all(x->ncols(x) == nrows(x) == n, v) + + vv = map(slope_eigenspace, v) + + d = Dict(v => [valuation_of_roots(k)] for (k,v) = vv[1]) + @assert sum(ncols(x) for x = keys(d)) == n + for i=2:length(vv) + dd = typeof(d)() + for (mat, pol_vec) = d + for (p, m) = vv[i] + j = _intersect(mat, m) + if ncols(j) > 0 + dd[j] = push!(copy(pol_vec), valuation_of_roots(p)) + end + end + end + d = dd + @assert sum(ncols(x) for x = keys(d)) == n + end - return TropI + return d end +# #======= +# tropical variety of an ideal +# todo: proper documentation +# Example: +# import Random +# K,s = RationalFunctionField(QQ,"s"); +# Kx,(x1,x2,x3,x4) = polynomial_ring(K,4); +# val = TropicalSemiringMap(K,s); +# I = ideal([x1-s*x2+(s+1)*x3,3*x2-s^2*x3+(s^2+1)*x4]); +# Random.seed!(3847598273423); +# TropI = tropical_variety(I,val) +# =======# +# function tropical_variety(I::MPolyIdeal, val::TropicalSemiringMap, convention::Union{typeof(min),typeof(max)}=min) + +# ### +# # Part 0: Preprocessing +# # Check whether valuation is on the coefficient ring of input polynomials, +# # homogenize input ideal if not homogeneous +# ### +# if coefficient_ring(base_ring(I))!=val.valued_field +# error("input valuation not on coefficient ring of input ideal") +# end +# was_input_homogeneous = true +# for g in groebner_basis(I,complete_reduction=true) # todo: replace GB computation with interreduction +# if !sloppy_is_homogeneous(g) +# was_input_homogeneous = false +# I = homogenize(I) +# break +# end +# end + + + +# ### +# # Part 1: Tropical starting polyhedra (todo: avoid recomputation) +# # - compute and recompute starting points until they lie in the relative interior of maximal cells +# # - initialize working lists +# ### + +# # Note: a working list entry consists of a triple (w,C,G) where +# # * G is a (tropical) Groebner basis +# # * C is the Groebner polyhedron +# # * w is the sum of vertices and rays of C +# # In particular: +# # * w is a weight vector with respect to which G is a Groebner basis, +# # * w is compatible with coordinate permutations if symmetries exist, +# # * instead of comparing C or G it suffices to compare w. +# working_list_todo = [] # list of groebner polyhedra with potentially unknown neighbours +# working_list_done = [] # list of groebner polyhedra with known neighbours +# facet_points_done = [] # list of facet points whose tropical links were computed and traversed + +# compute_starting_points = true +# while compute_starting_points +# print("computing random starting points... ") +# starting_points = tropical_points(I,val) +# println("done") + +# working_list_todo = [] +# working_list_done = [] +# facet_points_done = [] +# compute_starting_points = false +# for starting_point in starting_points +# print("computing groebner_basis for starting point ",starting_point,"... ") +# G = groebner_basis(I,val,starting_point) +# println("done") +# C = groebner_polyhedron(G,val,starting_point) +# w = anchor_point(C) + +# # if C is lower-dimensional, recompute all starting points +# if dim(C)!=dim(I) +# println("starting point on lower-dimensional cell, recomputing...") +# compute_starting_points = true +# break +# end + +# # if (w,C,G) already is in working_list_todo, skip +# i = searchsortedfirst(working_list_todo,(w,C,G),by=x->x[1]) +# if i<=length(working_list_todo) && working_list_todo[i][1]==w +# continue +# end +# # otherwise, add (w,C,G) to todo list +# insert!(working_list_todo, i, (w,C,G)) +# end +# end + + + +# ### +# # Part 2: Tropical traversal +# ### +# while !isempty(working_list_todo) +# print("#working_list_todo: ",length(working_list_todo)," ") +# println("#working_list_done: ",length(working_list_done)) + +# # pick a groebner polyhedron from todo list, add it to the done list, and compute its facet points +# (w,C,G) = popfirst!(working_list_todo) +# i = searchsortedfirst(working_list_done,(w,C,G),by=x->x[1]) +# insert!(working_list_done, i, (w,C,G)) + +# points_to_traverse = facet_points(C) +# for point_to_traverse in points_to_traverse +# # if point was traversed before, skip +# i = searchsortedfirst(facet_points_done,point_to_traverse) +# if i<=length(facet_points_done) && facet_points_done[i]==point_to_traverse +# continue +# end +# # otherwise add point_to_traverse to facet_points_done +# insert!(facet_points_done, i, point_to_traverse) + +# directions_to_traverse = tropical_link(ideal(G),val,point_to_traverse) # todo, this output can be wrong +# for direction_to_traverse in directions_to_traverse +# # compute neighbour +# print("computing groebner_basis for ",point_to_traverse,direction_to_traverse,"... ") +# G_neighbour = groebner_flip(G,val,w,point_to_traverse,direction_to_traverse) +# println("done") +# C_neighbour = groebner_polyhedron(G_neighbour,val,point_to_traverse,perturbation=direction_to_traverse) +# w_neighbour = anchor_point(C_neighbour) + +# # if neighbour is already in done list, skip +# i = searchsortedfirst(working_list_done, +# (w_neighbour,C_neighbour,G_neighbour), +# by=x->x[1]) +# if i<=length(working_list_done) && working_list_done[i][1]==w_neighbour +# continue +# end +# # if neighbour is already in todo list, skip +# i = searchsortedfirst(working_list_todo, +# (w_neighbour,C_neighbour,G_neighbour), +# by=x->x[1]) +# if i<=length(working_list_todo) && working_list_todo[i][1]==w_neighbour +# continue +# end +# # otherwise, add neighbour to todo list +# insert!(working_list_todo, i, (w_neighbour,C_neighbour,G_neighbour)) +# end +# end +# end + + + +# ### +# # Part 3: Postprocessing +# ### +# # 3.0: dehomogenize data if input was homogenized +# if !was_input_homogeneous +# n = length(gens(base_ring(I))) + +# # 3.0.1: dehomogenize Groebner polyhedra +# zeroth_unit_vector_as_row_vector = zeros(Int,1,n) +# zeroth_unit_vector_as_row_vector[1,1] = 1 +# dehomogenising_hyperplane = polyhedron((zeros(Int,0,n),zeros(Int,0)), +# (zeroth_unit_vector_as_row_vector,[1])) +# for wCG in working_list_done +# wCG[2] = intersect(wCG[2],dehomogenising_hyperplane) +# end +# # 3.0.2: check that initial ideals are distinct (todo) +# end + +# # 3.1: construct PolyhedralComplex +# # 3.1.1: construct incidence_matrix, vertices_and_rays, and far_vertices +# incidence_matrix = Vector{Vector{Int}}() +# verts_rays = Vector{Vector{Polymake.Rational}}() +# far_vertices = Vector{Int}() +# for (w,C,G) in working_list_done +# incidence_vector = Vector{Int}() +# for vert in vertices(C) +# i = findfirst(isequal(vert),verts_rays) +# if i === nothing +# # if vert does not occur in verts_rays +# # add it to verts_rays +# push!(verts_rays,vert) +# push!(incidence_vector,length(verts_rays)) +# else +# push!(incidence_vector,i) +# end +# end +# for ray in rays(C) +# i = findfirst(isequal(ray),verts_rays) +# if i === nothing || !(i in far_vertices) +# # if ray does not occur in verts_rays or if it occurs but not as a ray, +# # add it to verts_rays +# push!(verts_rays,ray) +# push!(far_vertices,length(verts_rays)) +# push!(incidence_vector,length(verts_rays)) +# else +# push!(incidence_vector,i) +# end +# end +# push!(incidence_matrix,incidence_vector) + +# end +# verts_rays_matrix = permutedims(reduce(hcat, verts_rays)) # convert Vector{Vector} to Matrix + +# # 3.1.2: construct lineality space +# (w,C,G) = first(working_list_done) +# lineality_space_gens = matrix(QQ,lineality_space(C)) + + + +# # 3.2: Construct lists for weight_vectors, initial_ideals and multiplicities +# weight_vectors = [w for (w,C,G) in working_list_done] +# initial_ideals = [ideal(initial(G,val,w)) for (w,C,G) in working_list_done] +# multiplicities = [multiplicity(inI) for inI in initial_ideals] + + + +# PC = polyhedral_complex(IncidenceMatrix(incidence_matrix), +# verts_rays_matrix, +# far_vertices, +# lineality_space_gens) + +# verts_rays_perm = collect(vertices_and_rays(PC)) +# verts_rays_perm = Vector{Int64}.(verts_rays_perm) +# permutation = [findfirst(isequal(l), verts_rays_perm) for l in verts_rays] +# # inc = [findall(c -> c, incidence_matrix[i, :]) for i in 1:size(incidence_matrix, 1)] +# new_incidence = [permutation[incidence] for incidence in incidence_matrix] +# mults = Dict(new_incidence[i] => multiplicities[i] for i in 1:length(working_list_done)) + +# TropI = TropicalVariety{typeof(max),true}(PC, mults) + + +# set_attribute!(TropI,:weight_vectors,weight_vectors) +# set_attribute!(TropI,:initial_ideals,initial_ideals) + +# return TropI +# end + -#======= -Example: -P = cube(4) -anchor_point(P) -facet_points(P) -=======# -function anchor_point(P::Polyhedron) - # compute the sum of vertices and rays in homogenized coordinates - pt = convert(Vector{QQFieldElem},sum([vertices(P)...,rays(P)...])) - pushfirst!(pt,nvertices(P)) - - # project to orthogonal complement of lineality space if necessary - if lineality_dim(P)>0 - pt = Polymake.Matrix{Polymake.Rational}(vcat(transpose(pt))) - Polymake.common.project_to_orthogonal_complement(pt, P.pm_polytope.LINEALITY_SPACE) - pt = convert(Matrix{QQFieldElem}, pt)[1,:] - end - - # rescale until first entry is 1 and remove it - pt = [pt[i]//pt[1] for i in 2:length(pt)] - return pt -end -function facet_points(P::Polyhedron) - points = [] - for facet in faces(P,dim(P)-1) - if length(vertices(facet))>0 # skipping facets at infinity - push!(points,anchor_point(facet)) - end - end - return points -end +# #======= +# Example: +# P = cube(4) +# anchor_point(P) +# facet_points(P) +# =======# +# function anchor_point(P::Polyhedron) +# # compute the sum of vertices and rays in homogenized coordinates +# pt = convert(Vector{QQFieldElem},sum([vertices(P)...,rays(P)...])) +# pushfirst!(pt,nvertices(P)) + +# # project to orthogonal complement of lineality space if necessary +# if lineality_dim(P)>0 +# pt = Polymake.Matrix{Polymake.Rational}(vcat(transpose(pt))) +# Polymake.common.project_to_orthogonal_complement(pt, P.pm_polytope.LINEALITY_SPACE) +# pt = convert(Matrix{QQFieldElem}, pt)[1,:] +# end + +# # rescale until first entry is 1 and remove it +# pt = [pt[i]//pt[1] for i in 2:length(pt)] +# return pt +# end + +# function facet_points(P::Polyhedron) +# points = [] +# for facet in faces(P,dim(P)-1) +# if length(vertices(facet))>0 # skipping facets at infinity +# push!(points,anchor_point(facet)) +# end +# end +# return points +# end diff --git a/src/TropicalGeometry/variety_supertype.jl b/src/TropicalGeometry/variety_supertype.jl index 9b973e0490d3..270b08158f1a 100644 --- a/src/TropicalGeometry/variety_supertype.jl +++ b/src/TropicalGeometry/variety_supertype.jl @@ -1,595 +1,258 @@ -### -# Tropical variety supertype in Oscar (not for public use) -# =================================== -### - - -### -# 0. Definition -# ------------- -# M = typeof(min) or typeof(max): -# min or max convention -# EMB = true or false: -# embedded or abstract -# see also: variety.jl, hypersurface.jl, curve.jl, linear_space.jl -### +################################################################################ +# +# Abstract tropical variety supertype +# =================================== +# +# Not for public use, see concrete subtypes: +# - TropicalVariety, see variety,jl +# - TropicalHypersurface, see hypersurface.jl +# - TropicalCurve, see curve.jl +# - TropicalLinearSpace, see linear_space.jl +# +################################################################################ + +# minOrMax distinguishes between min- and max-convention +# isEmbedded distinguishes embedded and abstract tropical varieties +abstract type TropicalVarietySupertype{minOrMax,isEmbedded} end + + + +################################################################################ +# +# Properties +# +################################################################################ +# if TropV isa TropicalLinearSpace, then polymake_object isa Polymake.matroid.ValuatedMatroid +# if TropV isa TropicalHypersurface, then polymake_object isa Polymake.tropical.Hypersurface +function pm_object(TropV::TropicalVarietySupertype) + @req has_attribute(TropV,:polymake_object) "no polymake object cached" + return get_attribute(TropV,:polymake_object) +end -abstract type TropicalVarietySupertype{M,EMB} end @doc raw""" - underlying_polyhedral_complex(TV) - -Return the underlying polyhedral complex of a tropical variety. - -#Examples -```jldoctest -julia> RR = TropicalSemiring(min) -Tropical semiring (min) - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x^2+y^2+2 -x^2 + y^2 + (2) - -julia> hyp1 = TropicalHypersurface(f) -min tropical hypersurface embedded in 2-dimensional Euclidean space + polyhedral_complex(TropV::TropicalVariety) -julia> pc = underlying_polyhedral_complex(hyp1) -Polyhedral complex in ambient dimension 2 -``` +Return the polyhedral complex of a tropical variety. """ -function underlying_polyhedral_complex(TV::TropicalVarietySupertype) +function polyhedral_complex(TV::TropicalVarietySupertype) return TV.polyhedralComplex end -### -# 1. Basic constructions -# ---------------------- -### - @doc raw""" - intersect(T1, T2) - -Intersect two tropical varieties. - -# Examples -```jldoctest -julia> RR = TropicalSemiring(min) -Tropical semiring (min) - -julia> S,(x,y) = RR["x","y"] -(Multivariate polynomial ring in 2 variables over tropical semiring (min), AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}[x, y]) - -julia> f1 = x+y+1 -x + y + (1) - -julia> f2 = x^2+y^2+RR(-6) -x^2 + y^2 + (-6) - -julia> hyp1 = TropicalHypersurface(f1) -min tropical hypersurface embedded in 2-dimensional Euclidean space - -julia> hyp2 = TropicalHypersurface(f2) -min tropical hypersurface embedded in 2-dimensional Euclidean space + ambient_dim(TropV::TropicalVariety) -julia> tv12 = intersect(hyp1, hyp2) -min tropical variety of dimension 1 embedded in 2-dimensional Euclidean space -``` +Return the ambient dimension of `TropV`. Requires `TropV` to be embedded. """ -function intersect(T1::TropicalVarietySupertype{M, EMB}, T2::TropicalVarietySupertype{M, EMB}) where {M, EMB} - return TropicalVariety{M, EMB}(common_refinement(T1.polyhedralComplex, T2.polyhedralComplex)) +function ambient_dim(TropV::TropicalVarietySupertype{minOrMax,true}) where minOrMax + return ambient_dim(TropV.polyhedralComplex) end @doc raw""" - intersect_stably(T1, T2) + codim(TropV::TropicalVariety) -# Examples +Return the codimension of `TropV`. Requires `TropV` to be embedded. """ -function stably_intersect(T1::TropicalVarietySupertype{M, EMB}, T2::TropicalVarietySupertype{M, EMB}) where {M, EMB} - return TropicalVariety{M, EMB}(intersect_stably(T1.polyhedralComplex,T2.polyhedralComplex)) +function codim(TropV::TropicalVarietySupertype{minOrMax,true}) where minOrMax + return codim(TropV.polyhedralComplex) end +function convention(TropV::TropicalVarietySupertype{typeof(min),isEmbedded}) where isEmbedded + return min +end +function convention(TropV::TropicalVarietySupertype{typeof(max),isEmbedded}) where isEmbedded + return max +end -### -# 2. Basic properties -# ------------------- -### @doc raw""" - ambient_dim(T::TropicalVariety{M, EMB}) - ambient_dim(T::TropicalCurve{M, EMB}) - ambient_dim(T::TropicalHypersurface{M, EMB}) - ambient_dim(T::TropicalLinearSpace{M, EMB}) - -Return the ambient dimension of `T` if it is embedded. Otherwise an error is thrown. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of ambient dimension n -```jldoctest -julia> RR = TropicalSemiring(min); + dim(TropV::TropicalVariety) -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> ambient_dim(tropicalLine) -2 -``` +Return the dimension of `TropV`. """ -function ambient_dim(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - if !EMB - error("ambient_dim: tropical variety not embedded") - end - - return ambient_dim(T.polyhedralComplex) +function dim(TropV::TropicalVarietySupertype) + return dim(TropV.polyhedralComplex) end - @doc raw""" - codim(T::TropicalVariety{M, EMB}) - codim(T::TropicalCurve{M, EMB}) - codim(T::TropicalHypersurface{M, EMB}) - codim(T::TropicalLinearSpace{M, EMB}) - -Return the codimension of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is always of dimension n-1 -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; + f_vector(TropV::TropicalVariety) -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> codim(tropicalLine) -1 -``` +Return the f-Vector of `TropV`. """ -function codim(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return codim(T.polyhedralComplex) +function f_vector(TropV::TropicalVarietySupertype) + return f_vector(TropV.polyhedralComplex) end - @doc raw""" - dim(T::TropicalVariety{M, EMB}) - dim(T::TropicalCurve{M, EMB}) - dim(T::TropicalHypersurface{M, EMB}) - dim(T::TropicalLinearSpace{M, EMB}) - -Return the dimension of `T`. + lineality_dim(TropV::TropicalVariety) -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is always of dimension n-1 -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> dim(tropicalLine) -1 -``` +Return the dimension of the lineality space of `TropV`. """ -function dim(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return dim(T.polyhedralComplex) +function lineality_dim(TropV::TropicalVarietySupertype) + return lineality_dim(TropV.polyhedralComplex) end - @doc raw""" - f_vector(T::TropicalVariety{M, EMB}) - f_vector(T::TropicalCurve{M, EMB}) - f_vector(T::TropicalHypersurface{M, EMB}) - f_vector(T::TropicalLinearSpace{M, EMB}) - -Return the f-Vector of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; + lineality_space(TropV::TropicalVariety) -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> f_vector(tropicalLine) -2-element Vector{Int64}: - 1 - 3 -``` +Return the lineality space of `TropV`. """ -function f_vector(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return f_vector(T.polyhedralComplex) +function lineality_space(TropV::TropicalVarietySupertype) + return lineality_space(TropV.polyhedralComplex) end - @doc raw""" - lineality_dim(T::TropicalVariety{M, EMB}) - lineality_dim(T::TropicalCurve{M, EMB}) - lineality_dim(T::TropicalHypersurface{M, EMB}) - lineality_dim(T::TropicalLinearSpace{M, EMB}) - -Return the dimension of the lineality space of `T` if it is embedded. Otherwise an error is thrown. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y; - -julia> tropicalAndAffineLine = TropicalHypersurface(f); + maximal_polyhedra(TropV::TropicalVariety) -julia> lineality_dim(tropicalAndAffineLine) -1 -``` +Return the maximal polyhedra of `TropV`. """ -function lineality_dim(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - if !EMB - error("lineality_dim: tropical variety not embedded") - end - - return lineality_dim(T.polyhedralComplex) +function maximal_polyhedra(TropV::TropicalVarietySupertype) + return maximal_polyhedra(TropV.polyhedralComplex) end - @doc raw""" - lineality_space(T::TropicalVariety{M, EMB}) - lineality_space(T::TropicalCurve{M, EMB}) - lineality_space(T::TropicalHypersurface{M, EMB}) - lineality_space(T::TropicalLinearSpace{M, EMB}) - -Return the lineality space of `T` if it is embedded. Otherwise an error is thrown. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality spaceension n -```jldoctest -julia> RR = TropicalSemiring(min); + maximal_polyhedra_and_multiplicities(TropV::TropicalVariety) -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y; - -julia> tropicalAndAffineLine = TropicalHypersurface(f); - -julia> lineality_space(tropicalAndAffineLine) -1-element SubObjectIterator{RayVector{QQFieldElem}}: - [-1, -1] -``` +Return the maximal polyhedra of `TropV`. """ -function lineality_space(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - if !EMB - error("lineality_space: tropical variety not embedded") - end - - return lineality_space(T.polyhedralComplex) +function maximal_polyhedra_and_multiplicities(TropV::TropicalVarietySupertype) + TropVmults = multiplicities(TropV) + return [ (sigma,TropVmults[sigma]) for sigma in maximal_polyhedra(TropV) ] end - @doc raw""" - maximal_polyhedra(T::TropicalVariety{M, EMB}) - maximal_polyhedra(T::TropicalCurve{M, EMB}) - maximal_polyhedra(T::TropicalHypersurface{M, EMB}) - maximal_polyhedra(T::TropicalLinearSpace{M, EMB}) - -Return the maximal polyhedra of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; + minimal_faces(TropV::TropicalVariety) -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> maximal_polyhedra(tropicalLine) -3-element SubObjectIterator{Polyhedron{QQFieldElem}}: - Polyhedron in ambient dimension 2 - Polyhedron in ambient dimension 2 - Polyhedron in ambient dimension 2 -``` +Return the minimal faces of `TropV`. """ -function maximal_polyhedra(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return maximal_polyhedra(T.polyhedralComplex) +function minimal_faces(TropV::TropicalVarietySupertype) + return minimal_faces(TropV.polyhedralComplex) end - -# todo: do maximal polyhedra at infinity count? @doc raw""" - n_maximal_polyhedra(T::TropicalVariety{M, EMB}) - n_maximal_polyhedra(T::TropicalCurve{M, EMB}) - n_maximal_polyhedra(T::TropicalHypersurface{M, EMB}) - n_maximal_polyhedra(T::TropicalLinearSpace{M, EMB}) + multiplicities(TropV::TropicalVariety) -Return the number of maximal polyhedra of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> n_maximal_polyhedra(tropicalLine) -3 -``` +Return the multiplicities of `TropV`. """ -function n_maximal_polyhedra(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return n_maximal_polyhedra(T.polyhedralComplex) +function multiplicities(TropV::TropicalVarietySupertype) + return TropV.multiplicities end - -# todo: do polyhedra at infinity count? @doc raw""" - npolyhedra(T::TropicalVariety{M, EMB}) - npolyhedra(T::TropicalCurve{M, EMB}) - npolyhedra(T::TropicalHypersurface{M, EMB}) - npolyhedra(T::TropicalLinearSpace{M, EMB}) - -Return the number of polyhedra of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); + n_maximal_polyhedra(TropV::TropicalVariety) -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> npolyhedra(tropicalLine) -4 -``` +Return the number of maximal polyhedra of `TropV`. """ -function npolyhedra(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return npolyhedra(T.polyhedralComplex) +function n_maximal_polyhedra(TropV::TropicalVarietySupertype) + return n_maximal_polyhedra(TropV.polyhedralComplex) end - -# todo: do vertices at infinity count? @doc raw""" - nvertices(T::TropicalVariety{M, EMB}) - nvertices(T::TropicalCurve{M, EMB}) - nvertices(T::TropicalHypersurface{M, EMB}) - nvertices(T::TropicalLinearSpace{M, EMB}) - -Return the number of vertices of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; + npolyhedra(TropV::TropicalVariety) -julia> tropicalLine = TropicalHypersurface(f); - -julia> nvertices(tropicalLine) -1 -``` +Return the number of polyhedra of `TropV`. """ -function nvertices(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return nvertices(T.polyhedralComplex) +function npolyhedra(TropV::TropicalVarietySupertype) + return npolyhedra(TropV.polyhedralComplex) end - - @doc raw""" - is_pure(T::TropicalVariety{M, EMB}) - is_pure(T::TropicalCurve{M, EMB}) - is_pure(T::TropicalHypersurface{M, EMB}) - is_pure(T::TropicalLinearSpace{M, EMB}) - -Return `true` if `T` is a pure polyhedral complex, `false` otherwise. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); + nvertices(TropV::TropicalVariety) -julia> is_pure(tropicalLine) -true -``` +Return the number of vertices of `TropV`. """ -function is_pure(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return is_pure(T.polyhedralComplex) +function nvertices(TropV::TropicalVarietySupertype) + return nvertices(TropV.polyhedralComplex) end - @doc raw""" - is_simplicial(T::TropicalVariety{M, EMB}) - is_simplicial(T::TropicalCurve{M, EMB}) - is_simplicial(T::TropicalHypersurface{M, EMB}) - is_simplicial(T::TropicalLinearSpace{M, EMB}) - -Return `true` if `T` is a simplicial polyhedral complex, `false` otherwise. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; + is_pure(TropV::TropicalVariety) -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> is_simplicial(tropicalLine) -true -``` +Return `true` if `TropV` is pure as a polyhedral complex, `false` otherwise. """ -function is_simplicial(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - return is_simplicial(T.polyhedralComplex) +function is_pure(TropV::TropicalVarietySupertype) + return is_pure(TropV.polyhedralComplex) end - @doc raw""" - vertices(T::TropicalVariety{M, EMB}) - vertices(T::TropicalCurve{M, EMB}) - vertices(T::TropicalHypersurface{M, EMB}) - vertices(T::TropicalLinearSpace{M, EMB}) + is_simplicial(TropV::TropicalVariety) -Return the vertices of `T`, which are points in euclidean space if T is embedded or elements in an ordered set otherwise. - -# Examples -The vertices of a plane tropical line, plane tropical honeycomb quadric, and plane tropical honeycomb cubic -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; - -julia> f1 = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f1); - -julia> vertices(tropicalLine) -1-element SubObjectIterator{PointVector{QQFieldElem}}: - [1, 1] - -julia> f2 = 1*x^2+x*y+1*y^2+x+y+1; - -julia> tropicalQuadric = TropicalHypersurface(f1); - -julia> vertices(tropicalQuadric) -1-element SubObjectIterator{PointVector{QQFieldElem}}: - [1, 1] +Return `true` if `TropV` is simplicial as a polyhedral complex, `false` otherwise. +""" +function is_simplicial(TropV::TropicalVarietySupertype) + return is_simplicial(TropV.polyhedralComplex) +end -julia> f3 = x^3+x*y^2+x^2*y+y^3+x^2+x*y+y^2+x+y+1; -julia> tropicalCubic = TropicalHypersurface(f3); +@doc raw""" + rays(TropV::TropicalVariety) -julia> vertices(tropicalCubic) -2-element SubObjectIterator{PointVector{QQFieldElem}}: - [0, 0] - [1, 1] -``` +Return the rays of `TropV`. """ -function vertices(as::Type{PointVector{S}}, T::TropicalVarietySupertype{M,EMB}) where {S,M,EMB} - return vertices(as,T.polyhedralComplex) +function rays(as::Type{RayVector{S}}, TropV::TropicalVarietySupertype{minOrMax,isEmbedded}) where {S,minOrMax,isEmbedded} + return rays(as,TropV.polyhedralComplex) end - -function vertices(T::TropicalVarietySupertype{M, EMB}) where {M,EMB} - return vertices(T.polyhedralComplex) +function rays(TropV::TropicalVarietySupertype) + return rays(TropV.polyhedralComplex) end - @doc raw""" - weights(T::TropicalVariety{M, EMB}) - weights(T::TropicalCurve{M, EMB}) - weights(T::TropicalHypersurface{M, EMB}) - weights(T::TropicalLinearSpace{M, EMB}) - -Return the weights of `T`. - -# Examples -A tropical hypersurface in $\mathbb{R}^n$ is of lineality dimension n -```jldoctest -julia> RR = TropicalSemiring(min); - -julia> S,(x,y) = RR["x","y"]; + rays_modulo_lineality(TropV::TropicalVariety) -julia> f = x+y+1; - -julia> tropicalLine = TropicalHypersurface(f); - -julia> weights(tropicalLine) -pm::Vector -1 1 1 -``` +Return the rays modulo the lineality space of `TropV`. """ -function weights(T::TropicalVarietySupertype{M,EMB}) where {M,EMB} - if !has_attribute(T,:weights) - error("weights: no weights attributed") - end - return get_attribute(T,:weights) +function rays_modulo_lineality(as::Type{RayVector{S}}, TropV::TropicalVarietySupertype{minOrMax,isEmbedded}) where {S,minOrMax,isEmbedded} + return rays_modulo_lineality(as,TropV.polyhedralComplex) +end +function rays_modulo_lineality(TropV::TropicalVarietySupertype) + return rays_modulo_lineality(TropV.polyhedralComplex) end +@doc raw""" + vertices_and_rays(TropV::TropicalVariety) -# @doc raw""" -# PolyhedralComplex(TV::TropicalVarietySupertype) - -# Return the underlying polyhedral complex. - -# # Examples -# ```jldoctest -# julia> RR = TropicalSemiring(min) -# Tropical ring (min) +Return the vertices and rays of `TropV`. +""" +function vertices_and_rays(TropV::TropicalVarietySupertype) + return vertices_and_rays(TropV.polyhedralComplex) +end -# julia> S,(x,y) = RR["x","y"] -# (Multivariate Polynomial Ring in x, y over Tropical ring (min), AbstractAlgebra.Generic.MPoly{Oscar.TropicalSemiringElem{typeof(min)}}[x, y]) -# julia> f = x+y+1 -# x + y + (1) +@doc raw""" + vertices(TropV::TropicalVariety) -# julia> hyp = TropicalHypersurface(f) -# A min tropical hypersurface embedded in 2-dimensional Euclidean space +Return the vertices of `TropV`. +""" +function vertices(as::Type{PointVector{S}}, TropV::TropicalVarietySupertype{minOrMax,isEmbedded}) where {S,minOrMax,isEmbedded} + return vertices(as,TropV.polyhedralComplex) +end +function vertices(TropV::TropicalVarietySupertype{minOrMax, isEmbedded}) where {minOrMax,isEmbedded} + return vertices(TropV.polyhedralComplex) +end -# julia> pc = PolyhedralComplex(hyp) -# A polyhedral complex in ambient dimension 3 -# julia> vertices(pc) -# 4-element SubObjectIterator{Union{PointVector{Polymake.Rational}, RayVector{Polymake.Rational}}}: -# [0, -1, -1] -# [0, 1, 0] -# [0, 0, 1] -# [0, 1, 1] +@doc raw""" + visualize(TropV::TropicalVariety) -# julia> for v in vertices(pc) -# println(typeof(v)) -# end -# RayVector{Polymake.Rational} -# RayVector{Polymake.Rational} -# RayVector{Polymake.Rational} -# PointVector{Polymake.Rational} -# ``` -# """ -# function PolyhedralComplex(TV::TropicalVarietySupertype{M, EMB}) where {M,EMB} -# return PolyhedralComplex(pm_object(TV)) -# end +Visualize `TropV`. +""" +function visualize(TropV::TropicalVarietySupertype) + return visualize(TropV.polyhedralComplex) +end diff --git a/src/exports.jl b/src/exports.jl index dbd6c34c60aa..4f5d878931fe 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -51,7 +51,6 @@ export CoveringMorphism export CyclicQuotientSingularity export DirectProductGroup export Directed -export DivisorOnTropicalCurve export Edge export EmptyScheme export FPGroup @@ -180,11 +179,11 @@ export ToricDivisorClass export ToricLineBundle export ToricMorphism export ToricVanishingSet -export TropicalCurve -export TropicalHypersurface -export TropicalLinearSpace -export TropicalSemiring -export TropicalSemiringMap +export TropicalCurve, tropical_curve +export TropicalHypersurface, tropical_hypersurface +export TropicalLinearSpace, tropical_linear_space +export TropicalSemiring, TropicalSemiringElem, tropical_semiring +export TropicalSemiringMap, tropical_semiring_map export TropicalVariety export Undirected export WreathProductGroup @@ -219,6 +218,10 @@ export affine_patch export affine_patches export affine_space export alexander_dual +export algebraic_ideal +export algebraic_matrix +export algebraic_polynomial +export algebraic_pluecker_vector export algebraic_set export all_atlas_group_infos export all_blocks @@ -247,7 +250,6 @@ export ambient_ring export ambient_scheme export ambient_space export ambient_type -export anchor_point export anti_symmetric_parts export anticanonical_bundle export anticanonical_divisor @@ -266,7 +268,6 @@ export atlas_subgroup export augmented_chow_ring export aut export automorphism_group -export base_curve export base_ring export base_ring_elem_type export base_ring_module @@ -323,7 +324,6 @@ export character_to_rational_function export characteristic_subgroups, has_characteristic_subgroups, set_characteristic_subgroups export charpoly export chief_series, has_chief_series, set_chief_series -export chip_firing_move export chow_ring export circuits export class_group @@ -527,7 +527,6 @@ export face_fan export faces export facet_degrees export facet_indices -export facet_points export facet_sizes export facets export factor_of_direct_product @@ -619,7 +618,6 @@ export groebner_basis_hilbert_driven export groebner_basis_modular export groebner_basis_with_transformation_matrix export groebner_fan -export groebner_polyhedron export group export gset export h_star_polynomial @@ -821,7 +819,6 @@ export is_isomorphism export is_k_separation export is_lattice_polytope export is_left -export is_linearly_equivalent export is_local export is_loopless export is_maximal_subgroup @@ -994,7 +991,7 @@ export maximal_cones export maximal_extension export maximal_groebner_cone export maximal_normal_subgroups, has_maximal_normal_subgroups, set_maximal_normal_subgroups -export maximal_polyhedra +export maximal_polyhedra, maximal_polyhedra_and_multiplicities export maximal_subgroup_reps export maximal_subgroups, has_maximal_subgroups, set_maximal_subgroups export metadata @@ -1046,6 +1043,7 @@ export multi_hilbert_series_reduced export multiplication_induced_morphism export multiplication_morphism export multiplicative_jordan_decomposition +export multiplicities export multiplicities_eigenvalues export multiplicity export n_cones @@ -1054,7 +1052,6 @@ export n_gon export n_maximal_cells export n_maximal_cones export n_maximal_polyhedra -export n_nodes export name export names_of_fusion_sources export natural_character @@ -1170,6 +1167,7 @@ export pile_polytope export pitman_stanley_polytope export plane_curve export platonic_solid +export pluecker_indices export point_coordinates export point_matrix export point_vector @@ -1245,7 +1243,6 @@ export rand_normal_polytope export rand_pseudo export rand_spherical_polytope export rand_subpolytope -export random_affine_linear_polynomials export rank export rank_action export rational_equivalence_class @@ -1387,6 +1384,7 @@ export special_linear_group export special_orthogonal_group export special_unitary_group export src +export stable_intersection export stable_set_polytope export standard_basis export standard_basis_with_transformation_matrix @@ -1399,7 +1397,6 @@ export star_subdivision export star_triangulations export strongly_connected_components export structure_sheaf -export structure_tropical_jacobian export sub export subalgebra_membership export subalgebra_membership_homogeneous @@ -1456,8 +1453,9 @@ export trivial_divisor export trivial_divisor_class export trivial_morphism export trivial_subgroup, has_trivial_subgroup, set_trivial_subgroup -export tropical_points +export tropical_matrix export tropical_polynomial +export tropical_pluecker_vector export tropical_variety export truncate export turn_denominator_into_polyhedron @@ -1468,7 +1466,6 @@ export two_neighbor_step export two_sided_ideal export underlying_glueing export underlying_morphism -export underlying_polyhedral_complex export underlying_quotient export underlying_scheme export uniform_matroid @@ -1482,9 +1479,7 @@ export upper_bound_g_vector export upper_bound_h_vector export upper_central_series, has_upper_central_series, set_upper_central_series export upper_triangular_matrix -export v_reduced export valuation_of_roots -export valued_weighted_degree export vamos_matroid export vanishing_ideal export vanishing_sets diff --git a/test/Serialization/PolynomialsSeries.jl b/test/Serialization/PolynomialsSeries.jl index 0ab609957eea..efb47face4c0 100644 --- a/test/Serialization/PolynomialsSeries.jl +++ b/test/Serialization/PolynomialsSeries.jl @@ -11,7 +11,7 @@ Zt, t = polynomial_ring(residue_ring(ZZ, 2), "t") Fin, d = finite_field(t^2 + t + 1) Frac = fraction_field(R) P7 = PadicField(7, 30) -T = TropicalSemiring() +T = tropical_semiring() F, o = Hecke.Nemo._FiniteField(4) Fs, s = F["s"] FF, r = Hecke.Nemo._FiniteField(s^2 + o * s + 1, "r") @@ -56,8 +56,8 @@ cases = [ end end end - - @testset "Multivariate Polynomial over $(case[4])" begin + + @testset "Multivariate Polynomial over $(case[4])" begin R, (z, w) = polynomial_ring(case[1], ["z", "w"]) p = z^2 + case[2] * z * w + case[3] * w^3 test_save_load_roundtrip(path, p) do loaded diff --git a/test/Serialization/TropicalGeometry.jl b/test/Serialization/TropicalGeometry.jl index d89f0b88be40..831d4b5febd2 100644 --- a/test/Serialization/TropicalGeometry.jl +++ b/test/Serialization/TropicalGeometry.jl @@ -1,35 +1,41 @@ @testset "Tropical Geometry" begin - mktempdir() do path - @testset "Tropical Curves" begin - IM = IncidenceMatrix([[1,2],[1,3],[1,4]]) - @testset "Abstract" begin - abs_TC = TropicalCurve(IM) - test_save_load_roundtrip(path, abs_TC) do loaded - @test graph(loaded) == graph(abs_TC) - end - end + mktempdir() do path + @testset "Tropical Curves" begin + @testset "Abstract" begin + Sigma = graph_from_adjacency_matrix(Undirected,[0 1 1; 1 0 1; 1 1 0]); + abs_TC = tropical_curve(Sigma, ones(ZZRingElem,ne(Sigma))) + test_save_load_roundtrip(path, abs_TC) do loaded + @test graph(loaded) == graph(abs_TC) + end + end - @testset "Embedded" begin - VR = [0 0; 1 0; -1 0; 0 1] - PC = polyhedral_complex(QQFieldElem, IM, VR) - TC = TropicalCurve(PC) - test_save_load_roundtrip(path, TC) do loaded - loaded_PC = underlying_polyhedral_complex(loaded) - @test nrays(PC) == nrays(loaded_PC) - @test n_maximal_polyhedra(PC) == n_maximal_polyhedra(loaded_PC) - @test dim(PC) == dim(loaded_PC) + @testset "Embedded" begin + IM = IncidenceMatrix([[1,2],[1,3],[1,4]]) + VR = [0 0; 1 0; -1 0; 0 1] + PC = polyhedral_complex(QQFieldElem, IM, VR) + TC = tropical_curve(PC) + test_save_load_roundtrip(path, TC) do loaded + loaded_PC = polyhedral_complex(loaded) + @test nrays(PC) == nrays(loaded_PC) + @test n_maximal_polyhedra(PC) == n_maximal_polyhedra(loaded_PC) + @test dim(PC) == dim(loaded_PC) + end + end end - end - end - @testset "Tropical Hypersurfaces" begin - T = TropicalSemiring(min) - Txy,(x,y) = T["x","y"] - f = x + y^2 - Tf = TropicalHypersurface(f) - test_save_load_roundtrip(path, Tf) do loaded - @test f == polynomial(loaded) - end + @testset "Tropical Hypersurfaces" begin + T = tropical_semiring(min) + Txy,(x,y) = T["x","y"] + f = x + y^2 + Tf = tropical_hypersurface(f) + + test_save_load_roundtrip(path, inf(T)) do loaded + @test inf(T) == loaded + end + + test_save_load_roundtrip(path, Tf) do loaded + @test f == tropical_polynomial(loaded) + end + end end - end end diff --git a/test/Serialization/basic_types.jl b/test/Serialization/basic_types.jl index 349d3b069ceb..17a8510244d3 100644 --- a/test/Serialization/basic_types.jl +++ b/test/Serialization/basic_types.jl @@ -1,7 +1,7 @@ @testset "basic_types" begin - + mktempdir() do path - @testset "Testing (de)serialization of $(T)" for T in + @testset "Testing (de)serialization of $(T)" for T in ( UInt, UInt8, UInt16, UInt32, UInt64, UInt128, Int, Int8, Int16, Int32, Int64, Int128, @@ -14,14 +14,14 @@ Nemo.fpField(UInt(7)), Nemo.FpField(ZZRingElem(7)), #PadicField(7, 30), - #TropicalSemiring() + #tropical_semiring() ) original = T(1) test_save_load_roundtrip(path, original) do loaded @test loaded == original end end - + @testset "String" begin original = "original" test_save_load_roundtrip(path, original) do loaded diff --git a/test/TropicalGeometry/groebner_basis.jl b/test/TropicalGeometry/groebner_basis.jl index cb84492209a4..47b9e61df884 100644 --- a/test/TropicalGeometry/groebner_basis.jl +++ b/test/TropicalGeometry/groebner_basis.jl @@ -1,173 +1,26 @@ -@testset "groebner_basis" begin - @testset "Cyclic5Homogenized" begin - Kx,(x0,x1,x2,x3,x4,x5) = polynomial_ring(QQ,6) - Cyclic5Homogenized = ideal([x1+x2+x3+x4+x5, - x1*x2+x2*x3+x3*x4+x1*x5+x4*x5, - x1*x2*x3+x2*x3*x4+x1*x2*x5+x1*x4*x5+x3*x4*x5, - x1*x2*x3*x4+x1*x2*x3*x5+x1*x2*x4*x5+x1*x3*x4*x5+x2*x3*x4*x5, - -x0^5+x1*x2*x3*x4*x5]) - w = [0,0,0,0,0,0] - @testset "val_2" begin - val_2 = TropicalSemiringMap(QQ,2) - computed = groebner_basis(Cyclic5Homogenized, val_2, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y3*y4*y5^2 + y3*y4*y5*y6 - y3*y4*y6^2 - y3*y5^2*y6 - y3*y5*y6^2 + y3*y6^3 + y4^2*y5*y6 + y4*y5^2*y6 + y4*y6^3 - y5^3*y6 - 2*y5^2*y6^2 - y5*y6^3 + y6^4 - y3*y4^2 - y3*y4*y5 + y3*y5*y6 - y3*y6^2 + y4^2*y5 - y4^2*y6 + y4*y5*y6 - 2*y4*y6^2 + y5^2*y6 + y5*y6^2 - y6^3 - -2*y3*y4*y5*y6^2 + 3*y3*y4*y6^3 - y3*y5^3*y6 - y3*y5^2*y6^2 + 2*y3*y5*y6^3 - y3*y6^4 + y4^2*y5^3 - y4^2*y5*y6^2 + y4^2*y6^3 - 2*y4*y5^2*y6^2 + 4*y4*y5*y6^3 - y5^4*y6 - 3*y5^3*y6^2 - y5^2*y6^3 + 3*y5*y6^4 - y6^5 - -11*y3*y4*y5*y6^4 - 6*y3*y4*y6^5 - 19*y3*y5^3*y6^3 + 16*y3*y5^2*y6^4 + 46*y3*y5*y6^5 - 26*y3*y6^6 - 6*y4^3*y6^4 - y4^2*y5*y6^4 - 28*y4^2*y6^5 + 16*y4*y5^3*y6^3 - 9*y4*y5^2*y6^4 + 19*y4*y5*y6^5 - 48*y4*y6^6 + y5^5*y6^2 - 9*y5^4*y6^3 + 7*y5^3*y6^4 + 48*y5^2*y6^5 + 36*y5*y6^6 - 26*y6^7 - -y3*y4*y5*y6 - y3*y4*y6^2 + y3*y5^2*y6 + 4*y3*y5*y6^2 - 3*y3*y6^3 + y4^3*y5 - y4^3*y6 - y4^2*y5^2 + 3*y4^2*y5*y6 - 4*y4^2*y6^2 + 2*y4*y5*y6^2 - 6*y4*y6^3 + y5^3*y6 + 5*y5^2*y6^2 + 3*y5*y6^3 - 3*y6^4 - -4*y3*y4*y5*y6^3 + 21*y3*y4*y6^4 - 3*y3*y5^3*y6^2 - 15*y3*y5^2*y6^3 - 12*y3*y5*y6^4 + 13*y3*y6^5 + y4^4*y6^2 + 9*y4^3*y6^3 - 3*y4^2*y5*y6^3 + 32*y4^2*y6^4 - 16*y4*y5^3*y6^2 - 16*y4*y5^2*y6^3 + 14*y4*y5*y6^4 + 37*y4*y6^5 - 4*y5^4*y6^2 - 28*y5^3*y6^3 - 37*y5^2*y6^4 - 2*y5*y6^5 + 13*y6^6 - y3^2 + y3*y5 + 2*y3*y6 - y4*y5 + y4*y6 + y6^2 - 2*y3*y4*y6^4 + 4*y3*y5^3*y6^2 - 2*y3*y5^2*y6^3 - 8*y3*y5*y6^4 + 4*y3*y6^5 + y4^3*y6^3 - y4^2*y5*y6^3 + 5*y4^2*y6^4 + y4*y5^4*y6 - 3*y4*y5^3*y6^2 - 4*y4*y5*y6^4 + 8*y4*y6^5 + 3*y5^4*y6^2 - 8*y5^2*y6^4 - 6*y5*y6^5 + 4*y6^6 - -y3*y4*y5*y6^2 + 4*y3*y4*y6^3 - y3*y5^3*y6 - 2*y3*y5^2*y6^2 - 2*y3*y5*y6^3 + 2*y3*y6^4 + y4^3*y6^2 + y4^2*y5^2*y6 - y4^2*y5*y6^2 + 5*y4^2*y6^3 - 3*y4*y5^3*y6 - 2*y4*y5^2*y6^2 + 3*y4*y5*y6^3 + 6*y4*y6^4 - y5^4*y6 - 5*y5^3*y6^2 - 6*y5^2*y6^3 + 2*y6^5 - y1^5 - 2*y3*y4*y5*y6^2 + y3*y4*y6^3 + 2*y3*y5*y6^3 - y3*y6^4 - y4^2*y5*y6^2 - 2*y4*y5^2*y6^2 + y4*y5*y6^3 - y4*y6^4 + y5^2*y6^3 + 2*y5*y6^4 - y6^5 - -8*y3*y4*y5*y6^3 - 3*y3*y4*y6^4 + y3*y5^4*y6 - 11*y3*y5^3*y6^2 + 9*y3*y5^2*y6^3 + 29*y3*y5*y6^4 - 17*y3*y6^5 - 4*y4^3*y6^3 - y4^2*y5*y6^3 - 18*y4^2*y6^4 + 11*y4*y5^3*y6^2 - 6*y4*y5^2*y6^3 + 12*y4*y5*y6^4 - 31*y4*y6^5 + y5^5*y6 - 5*y5^4*y6^2 + 5*y5^3*y6^3 + 30*y5^2*y6^4 + 23*y5*y6^5 - 17*y6^6 - y2 + y3 + y4 + y5 + y6] - @test_skip computed == expected - end +@testset "src/TropicalGeometry/groebner_basis.jl" begin - @testset "val_3" begin - val_3 = TropicalSemiringMap(QQ,3) - computed = groebner_basis(Cyclic5Homogenized, val_3, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [-2*y3*y4*y5*y6^2 + 3*y3*y4*y6^3 - y3*y5^3*y6 - y3*y5^2*y6^2 + 2*y3*y5*y6^3 - y3*y6^4 + y4^2*y5^3 - y4^2*y5*y6^2 + y4^2*y6^3 - 2*y4*y5^2*y6^2 + 4*y4*y5*y6^3 - y5^4*y6 - 3*y5^3*y6^2 - y5^2*y6^3 + 3*y5*y6^4 - y6^5 - -11*y3*y4*y5*y6^4 - 6*y3*y4*y6^5 - 19*y3*y5^3*y6^3 + 16*y3*y5^2*y6^4 + 46*y3*y5*y6^5 - 26*y3*y6^6 - 6*y4^3*y6^4 - y4^2*y5*y6^4 - 28*y4^2*y6^5 + 16*y4*y5^3*y6^3 - 9*y4*y5^2*y6^4 + 19*y4*y5*y6^5 - 48*y4*y6^6 + y5^5*y6^2 - 9*y5^4*y6^3 + 7*y5^3*y6^4 + 48*y5^2*y6^5 + 36*y5*y6^6 - 26*y6^7 - -y3*y4*y5*y6^2 + 4*y3*y4*y6^3 - y3*y5^3*y6 - 2*y3*y5^2*y6^2 - 2*y3*y5*y6^3 + 2*y3*y6^4 + y4^3*y6^2 + y4^2*y5^2*y6 - y4^2*y5*y6^2 + 5*y4^2*y6^3 - 3*y4*y5^3*y6 - 2*y4*y5^2*y6^2 + 3*y4*y5*y6^3 + 6*y4*y6^4 - y5^4*y6 - 5*y5^3*y6^2 - 6*y5^2*y6^3 + 2*y6^5 - 2*y3*y4*y6^4 + 4*y3*y5^3*y6^2 - 2*y3*y5^2*y6^3 - 8*y3*y5*y6^4 + 4*y3*y6^5 + y4^3*y6^3 - y4^2*y5*y6^3 + 5*y4^2*y6^4 + y4*y5^4*y6 - 3*y4*y5^3*y6^2 - 4*y4*y5*y6^4 + 8*y4*y6^5 + 3*y5^4*y6^2 - 8*y5^2*y6^4 - 6*y5*y6^5 + 4*y6^6 - -y3*y4*y5*y6 - y3*y4*y6^2 + y3*y5^2*y6 + 4*y3*y5*y6^2 - 3*y3*y6^3 + y4^3*y5 - y4^3*y6 - y4^2*y5^2 + 3*y4^2*y5*y6 - 4*y4^2*y6^2 + 2*y4*y5*y6^2 - 6*y4*y6^3 + y5^3*y6 + 5*y5^2*y6^2 + 3*y5*y6^3 - 3*y6^4 - -4*y3*y4*y5*y6^3 + 21*y3*y4*y6^4 - 3*y3*y5^3*y6^2 - 15*y3*y5^2*y6^3 - 12*y3*y5*y6^4 + 13*y3*y6^5 + y4^4*y6^2 + 9*y4^3*y6^3 - 3*y4^2*y5*y6^3 + 32*y4^2*y6^4 - 16*y4*y5^3*y6^2 - 16*y4*y5^2*y6^3 + 14*y4*y5*y6^4 + 37*y4*y6^5 - 4*y5^4*y6^2 - 28*y5^3*y6^3 - 37*y5^2*y6^4 - 2*y5*y6^5 + 13*y6^6 - -8*y3*y4*y5*y6^3 - 3*y3*y4*y6^4 + y3*y5^4*y6 - 11*y3*y5^3*y6^2 + 9*y3*y5^2*y6^3 + 29*y3*y5*y6^4 - 17*y3*y6^5 - 4*y4^3*y6^3 - y4^2*y5*y6^3 - 18*y4^2*y6^4 + 11*y4*y5^3*y6^2 - 6*y4*y5^2*y6^3 + 12*y4*y5*y6^4 - 31*y4*y6^5 + y5^5*y6 - 5*y5^4*y6^2 + 5*y5^3*y6^3 + 30*y5^2*y6^4 + 23*y5*y6^5 - 17*y6^6 - y3*y4*y5^2 + y3*y4*y5*y6 - y3*y4*y6^2 - y3*y5^2*y6 - y3*y5*y6^2 + y3*y6^3 + y4^2*y5*y6 + y4*y5^2*y6 + y4*y6^3 - y5^3*y6 - 2*y5^2*y6^2 - y5*y6^3 + y6^4 - y3*y4^2 - y3*y4*y5 + y3*y5*y6 - y3*y6^2 + y4^2*y5 - y4^2*y6 + y4*y5*y6 - 2*y4*y6^2 + y5^2*y6 + y5*y6^2 - y6^3 - y3^2 + y3*y5 + 2*y3*y6 - y4*y5 + y4*y6 + y6^2 - y2 + y3 + y4 + y5 + y6 - y1^5 - 2*y3*y4*y5*y6^2 + y3*y4*y6^3 + 2*y3*y5*y6^3 - y3*y6^4 - y4^2*y5*y6^2 - 2*y4*y5^2*y6^2 + y4*y5*y6^3 - y4*y6^4 + y5^2*y6^3 + 2*y5*y6^4 - y6^5] - @test_skip computed == expected - end - end - - @testset "Katsura5Homogenized" begin - Kx,(x0,x1,x2,x3,x4,x5) = polynomial_ring(QQ,6) - Katsura5Homogenized = ideal([-x0+x1+2*x2+2*x3+2*x4+2*x5, - -x0*x1+x1^2+2*x2^2+2*x3^2+2*x4^2+2*x5^2, - -x0*x2+2*x1*x2+2*x2*x3+2*x3*x4+2*x4*x5, - x2^2-x0*x3+2*x1*x3+2*x2*x4+2*x3*x5, - 2*x2*x3-x0*x4+2*x1*x4+2*x2*x5]) - w = [0,0,0,0,0,0] - @testset "val_2" begin - val_2 = TropicalSemiringMap(QQ,2) - computed = groebner_basis(Katsura5Homogenized, val_2, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y2^4*y6 - 311*y2^3*y6^2 - 3480*y2^2*y6^3 - 1234*y2*y4*y6^3 - 5*y2*y5^2*y6^2 - 1162*y2*y5*y6^3 - 7542*y2*y6^4 + 8586*y3*y5^2*y6^2 - 39118*y3*y5*y6^3 - 6120*y3*y6^4 - 1660*y4*y5^2*y6^2 + 2232*y4*y5*y6^3 - 5060*y4*y6^4 + 1172*y5^4*y6 - 3110*y5^3*y6^2 + 1416*y5^2*y6^3 + 2176*y5*y6^4 + 11332*y6^5 - 10*y2^2*y6 - 6*y2*y4*y6 + 37*y2*y5^2 - 2*y2*y5*y6 + 18*y2*y6^2 - 98*y3*y5^2 + 118*y3*y5*y6 + 24*y3*y6^2 - 124*y4*y5^2 + 24*y4*y5*y6 + 20*y4*y6^2 - 74*y5^3 - 112*y5^2*y6 + 8*y5*y6^2 - 28*y6^3 - -1957*y2^3*y6 - 20993*y2^2*y6^2 - 8830*y2*y4*y6^2 + 8*y2*y5^2*y6 - 7894*y2*y5*y6^2 - 47370*y2*y6^3 + 52136*y3*y5^2*y6 - 241980*y3*y5*y6^2 - 37832*y3*y6^3 - 9540*y4*y5^2*y6 + 12936*y4*y5*y6^2 - 30244*y4*y6^3 + 7194*y5^4 - 18880*y5^3*y6 + 9076*y5^2*y6^2 + 13928*y5*y6^3 + 70320*y6^4 - 1957*y2^3*y5*y6 + 2016*y2^3*y6^2 + 20993*y2^2*y5*y6^2 + 25242*y2^2*y6^3 + 8830*y2*y4*y5*y6^2 + 19082*y2*y4*y6^3 - 8*y2*y5^3*y6 + 7891*y2*y5^2*y6^2 + 71922*y2*y5*y6^3 + 79618*y2*y6^4 - 52136*y3*y5^3*y6 + 237110*y3*y5^2*y6^2 + 376690*y3*y5*y6^3 + 40856*y3*y6^4 + 9540*y4*y5^3*y6 + 14892*y4*y5^2*y6^2 + 22220*y4*y5*y6^3 + 38388*y4*y6^4 + 18528*y5^4*y6 + 57614*y5^3*y6^2 + 34908*y5^2*y6^3 - 102196*y5*y6^4 - 106876*y6^5 - 8882351160*y2^3*y6 + 95295775448*y2^2*y6^2 + 40069075092*y2*y4*y6^2 + y2*y5^3 + 14046703*y2*y5^2*y6 + 35826240740*y2*y5*y6^2 + 215025506808*y2*y6^3 - 236766111212*y3*y5^2*y6 + 1098449475000*y3*y5*y6^2 + 171742990416*y3*y6^3 + 43130996630*y4*y5^2*y6 - 58680721228*y4*y5*y6^2 + 137297443936*y4*y6^3 - 32651831500*y5^4 + 85591054414*y5^3*y6 - 41346207054*y5^2*y6^2 - 63204945956*y5*y6^3 - 319203633416*y6^4 - 8220*y2^3*y6 + 88190*y2^2*y6^2 + 37082*y2*y4*y6^2 + 13*y2*y5^2*y6 + 33156*y2*y5*y6^2 + 198994*y2*y6^3 - 219108*y3*y5^2*y6 + 1016546*y3*y5*y6^2 + 158936*y3*y6^3 + 2*y4*y5^3 + 39916*y4*y5^2*y6 - 54304*y4*y5*y6^2 + 127060*y4*y6^3 - 30216*y5^4 + 79212*y5^3*y6 - 38260*y5^2*y6^2 - 58492*y5*y6^3 - 295404*y6^4 - -2*y2^2*y6 + y2*y4*y5 + 2*y2*y4*y6 - 6*y2*y5^2 + 3*y2*y5*y6 - 2*y2*y6^2 + 22*y3*y5^2 - 18*y3*y5*y6 - 4*y3*y6^2 + 24*y4*y5^2 - 4*y4*y5*y6 - 4*y4*y6^2 + 14*y5^3 + 20*y5^2*y6 - 4*y5*y6^2 + 4*y6^3 - y1 - y2 - 2*y3 - 2*y4 - 2*y5 - 2*y6 - y2*y6 + 2*y3*y5 + y4^2 + 2*y4*y5 + y5^2 - y6^2 - y2*y4 + y2*y5 + 2*y2*y6 + y3^2 + 4*y3*y5 + 2*y3*y6 - 2*y5*y6 - 2*y6^2 - y2^2*y4 + 2*y2^2*y6 + 2*y2*y4*y6 + 9*y2*y5^2 - 6*y2*y5*y6 + 2*y2*y6^2 - 34*y3*y5^2 + 16*y3*y5*y6 + 8*y3*y6^2 - 50*y4*y5^2 + 8*y4*y5*y6 - 26*y5^3 - 38*y5^2*y6 + 8*y5*y6^2 - 4*y6^3 - y2^2*y5 + 4*y2^2*y6 - 4*y2*y4*y6 + 10*y2*y5^2 + 2*y2*y5*y6 + 4*y2*y6^2 - 16*y3*y5^2 + 40*y3*y5*y6 + 8*y3*y6^2 - 24*y4*y5^2 + 4*y4*y5*y6 + 8*y4*y6^2 - 16*y5^3 - 28*y5^2*y6 - 4*y5*y6^2 - 8*y6^3 - y2*y5 + 2*y3*y4 - 2*y3*y5 + 2*y3*y6 - 2*y4*y5 - 2*y5^2 - 2*y5*y6 - y2*y3 + 2*y2*y4 + 2*y2*y5 + 4*y2*y6 + 6*y3*y5 + 2*y3*y6 + 2*y4*y5 - 2*y5*y6 - 4*y6^2 - 54153360*y2^3*y6 + 580993291*y2^2*y6^2 + 244290617*y2*y4*y6^2 + 85639*y2*y5^2*y6 + 218423171*y2*y5*y6^2 + 1310953987*y2*y6^3 + y3*y5^3 - 1443500738*y3*y5^2*y6 + 6696957681*y3*y5*y6^2 + 1047071864*y3*y6^3 + 262958349*y4*y5^2*y6 - 357760932*y4*y5*y6^2 + 837066422*y4*y6^3 - 199069633*y5^4 + 521826158*y5^3*y6 - 252076955*y5^2*y6^2 - 385343940*y5*y6^3 - 1946100638*y6^4] - @test_skip computed == expected - end - - @testset "val_3" begin - val_3 = TropicalSemiringMap(QQ,3) - computed = groebner_basis(Katsura5Homogenized, val_3, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [8882351160*y2^3*y6 + 95295775448*y2^2*y6^2 + 40069075092*y2*y4*y6^2 + y2*y5^3 + 14046703*y2*y5^2*y6 + 35826240740*y2*y5*y6^2 + 215025506808*y2*y6^3 - 236766111212*y3*y5^2*y6 + 1098449475000*y3*y5*y6^2 + 171742990416*y3*y6^3 + 43130996630*y4*y5^2*y6 - 58680721228*y4*y5*y6^2 + 137297443936*y4*y6^3 - 32651831500*y5^4 + 85591054414*y5^3*y6 - 41346207054*y5^2*y6^2 - 63204945956*y5*y6^3 - 319203633416*y6^4 - 2016*y2^3*y6^2 + 25242*y2^2*y6^3 + 19082*y2*y4*y6^3 - 3*y2*y5^2*y6^2 + 24552*y2*y5*y6^3 + 79618*y2*y6^4 - 4870*y3*y5^2*y6^2 + 338858*y3*y5*y6^3 + 40856*y3*y6^4 + 27828*y4*y5^2*y6^2 - 8024*y4*y5*y6^3 + 38388*y4*y6^4 + 7194*y5^5 - 352*y5^4*y6 + 66690*y5^3*y6^2 + 48836*y5^2*y6^3 - 31876*y5*y6^4 - 106876*y6^5 - y2^2*y5 + 4*y2^2*y6 - 4*y2*y4*y6 + 10*y2*y5^2 + 2*y2*y5*y6 + 4*y2*y6^2 - 16*y3*y5^2 + 40*y3*y5*y6 + 8*y3*y6^2 - 24*y4*y5^2 + 4*y4*y5*y6 + 8*y4*y6^2 - 16*y5^3 - 28*y5^2*y6 - 4*y5*y6^2 - 8*y6^3 - -1957*y2^3*y6 - 20993*y2^2*y6^2 - 8830*y2*y4*y6^2 + 8*y2*y5^2*y6 - 7894*y2*y5*y6^2 - 47370*y2*y6^3 + 52136*y3*y5^2*y6 - 241980*y3*y5*y6^2 - 37832*y3*y6^3 - 9540*y4*y5^2*y6 + 12936*y4*y5*y6^2 - 30244*y4*y6^3 + 7194*y5^4 - 18880*y5^3*y6 + 9076*y5^2*y6^2 + 13928*y5*y6^3 + 70320*y6^4 - y2*y6 + 2*y3*y5 + y4^2 + 2*y4*y5 + y5^2 - y6^2 - y2*y3 + 2*y2*y4 + 2*y2*y5 + 4*y2*y6 + 6*y3*y5 + 2*y3*y6 + 2*y4*y5 - 2*y5*y6 - 4*y6^2 - -2*y2^2*y6 + y2*y4*y5 + 2*y2*y4*y6 - 6*y2*y5^2 + 3*y2*y5*y6 - 2*y2*y6^2 + 22*y3*y5^2 - 18*y3*y5*y6 - 4*y3*y6^2 + 24*y4*y5^2 - 4*y4*y5*y6 - 4*y4*y6^2 + 14*y5^3 + 20*y5^2*y6 - 4*y5*y6^2 + 4*y6^3 - y2^4*y6 - 311*y2^3*y6^2 - 3480*y2^2*y6^3 - 1234*y2*y4*y6^3 - 5*y2*y5^2*y6^2 - 1162*y2*y5*y6^3 - 7542*y2*y6^4 + 8586*y3*y5^2*y6^2 - 39118*y3*y5*y6^3 - 6120*y3*y6^4 - 1660*y4*y5^2*y6^2 + 2232*y4*y5*y6^3 - 5060*y4*y6^4 + 1172*y5^4*y6 - 3110*y5^3*y6^2 + 1416*y5^2*y6^3 + 2176*y5*y6^4 + 11332*y6^5 - y2*y5 + 2*y3*y4 - 2*y3*y5 + 2*y3*y6 - 2*y4*y5 - 2*y5^2 - 2*y5*y6 - y2*y4 + y2*y5 + 2*y2*y6 + y3^2 + 4*y3*y5 + 2*y3*y6 - 2*y5*y6 - 2*y6^2 - 10*y2^2*y6 - 6*y2*y4*y6 + 37*y2*y5^2 - 2*y2*y5*y6 + 18*y2*y6^2 - 98*y3*y5^2 + 118*y3*y5*y6 + 24*y3*y6^2 - 124*y4*y5^2 + 24*y4*y5*y6 + 20*y4*y6^2 - 74*y5^3 - 112*y5^2*y6 + 8*y5*y6^2 - 28*y6^3 - 8220*y2^3*y6 + 88190*y2^2*y6^2 + 37082*y2*y4*y6^2 + 13*y2*y5^2*y6 + 33156*y2*y5*y6^2 + 198994*y2*y6^3 - 219108*y3*y5^2*y6 + 1016546*y3*y5*y6^2 + 158936*y3*y6^3 + 2*y4*y5^3 + 39916*y4*y5^2*y6 - 54304*y4*y5*y6^2 + 127060*y4*y6^3 - 30216*y5^4 + 79212*y5^3*y6 - 38260*y5^2*y6^2 - 58492*y5*y6^3 - 295404*y6^4 - y2^2*y4 + 2*y2^2*y6 + 2*y2*y4*y6 + 9*y2*y5^2 - 6*y2*y5*y6 + 2*y2*y6^2 - 34*y3*y5^2 + 16*y3*y5*y6 + 8*y3*y6^2 - 50*y4*y5^2 + 8*y4*y5*y6 - 26*y5^3 - 38*y5^2*y6 + 8*y5*y6^2 - 4*y6^3 - 54153360*y2^3*y6 + 580993291*y2^2*y6^2 + 244290617*y2*y4*y6^2 + 85639*y2*y5^2*y6 + 218423171*y2*y5*y6^2 + 1310953987*y2*y6^3 + y3*y5^3 - 1443500738*y3*y5^2*y6 + 6696957681*y3*y5*y6^2 + 1047071864*y3*y6^3 + 262958349*y4*y5^2*y6 - 357760932*y4*y5*y6^2 + 837066422*y4*y6^3 - 199069633*y5^4 + 521826158*y5^3*y6 - 252076955*y5^2*y6^2 - 385343940*y5*y6^3 - 1946100638*y6^4 - y1 - y2 - 2*y3 - 2*y4 - 2*y5 - 2*y6] - @test_skip computed == expected - end - end + @testset "groebner_basis(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector)" begin + R,(x,y) = QQ["x","y"] + I = ideal(R,[x^2+8*y^2,x+y]) + w = [1,-1] + nuMin = tropical_semiring_map(QQ) + nuMax = tropical_semiring_map(QQ,max) + @test issetequal(groebner_basis(I,nuMin,w),[x^2,x+y]) # trivial, min + @test issetequal(groebner_basis(I,nuMax,w),[y^2,x+y]) # trivial, max - @testset "val_t" begin - Kt,t = rational_function_field(QQ,"t") - Ktx,(x0,x1,x2,x3,x4,x5) = polynomial_ring(Kt,6) - Cyclic5Homogenized = ideal([x1+x2+x3+x4+x5, - x1*x2+x2*x3+x3*x4+x1*x5+x4*x5, - x1*x2*x3+x2*x3*x4+x1*x2*x5+x1*x4*x5+x3*x4*x5, - x1*x2*x3*x4+x1*x2*x3*x5+x1*x2*x4*x5+x1*x3*x4*x5+x2*x3*x4*x5, - -x0^5+x1*x2*x3*x4*x5]) - Katsura5Homogenized = ideal([-x0+x1+2*x2+2*x3+2*x4+2*x5, - -x0*x1+x1^2+2*x2^2+2*x3^2+2*x4^2+2*x5^2, - -x0*x2+2*x1*x2+2*x2*x3+2*x3*x4+2*x4*x5, - x2^2-x0*x3+2*x1*x3+2*x2*x4+2*x3*x5, - 2*x2*x3-x0*x4+2*x1*x4+2*x2*x5]) - w = [0,0,0,0,0,0] - val_t = TropicalSemiringMap(Kt,t) - @testset "Cyclic5Homogenized" begin - computed = groebner_basis(Cyclic5Homogenized, val_t, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [11*y3*y4*y5*y6^4 + 6*y3*y4*y6^5 + 19*y3*y5^3*y6^3 - 16*y3*y5^2*y6^4 - 46*y3*y5*y6^5 + 26*y3*y6^6 + 6*y4^3*y6^4 + y4^2*y5*y6^4 + 28*y4^2*y6^5 - 16*y4*y5^3*y6^3 + 9*y4*y5^2*y6^4 - 19*y4*y5*y6^5 + 48*y4*y6^6 - y5^5*y6^2 + 9*y5^4*y6^3 - 7*y5^3*y6^4 - 48*y5^2*y6^5 - 36*y5*y6^6 + 26*y6^7 - -2*y3*y4*y6^4 - 4*y3*y5^3*y6^2 + 2*y3*y5^2*y6^3 + 8*y3*y5*y6^4 - 4*y3*y6^5 - y4^3*y6^3 + y4^2*y5*y6^3 - 5*y4^2*y6^4 - y4*y5^4*y6 + 3*y4*y5^3*y6^2 + 4*y4*y5*y6^4 - 8*y4*y6^5 - 3*y5^4*y6^2 + 8*y5^2*y6^4 + 6*y5*y6^5 - 4*y6^6 - y3*y4*y5*y6^2 - 4*y3*y4*y6^3 + y3*y5^3*y6 + 2*y3*y5^2*y6^2 + 2*y3*y5*y6^3 - 2*y3*y6^4 - y4^3*y6^2 - y4^2*y5^2*y6 + y4^2*y5*y6^2 - 5*y4^2*y6^3 + 3*y4*y5^3*y6 + 2*y4*y5^2*y6^2 - 3*y4*y5*y6^3 - 6*y4*y6^4 + y5^4*y6 + 5*y5^3*y6^2 + 6*y5^2*y6^3 - 2*y6^5 - 2*y3*y4*y5*y6^2 - 3*y3*y4*y6^3 + y3*y5^3*y6 + y3*y5^2*y6^2 - 2*y3*y5*y6^3 + y3*y6^4 - y4^2*y5^3 + y4^2*y5*y6^2 - y4^2*y6^3 + 2*y4*y5^2*y6^2 - 4*y4*y5*y6^3 + y5^4*y6 + 3*y5^3*y6^2 + y5^2*y6^3 - 3*y5*y6^4 + y6^5 - -y3*y4*y5*y6 - y3*y4*y6^2 + y3*y5^2*y6 + 4*y3*y5*y6^2 - 3*y3*y6^3 + y4^3*y5 - y4^3*y6 - y4^2*y5^2 + 3*y4^2*y5*y6 - 4*y4^2*y6^2 + 2*y4*y5*y6^2 - 6*y4*y6^3 + y5^3*y6 + 5*y5^2*y6^2 + 3*y5*y6^3 - 3*y6^4 - 4*y3*y4*y5*y6^3 - 21*y3*y4*y6^4 + 3*y3*y5^3*y6^2 + 15*y3*y5^2*y6^3 + 12*y3*y5*y6^4 - 13*y3*y6^5 - y4^4*y6^2 - 9*y4^3*y6^3 + 3*y4^2*y5*y6^3 - 32*y4^2*y6^4 + 16*y4*y5^3*y6^2 + 16*y4*y5^2*y6^3 - 14*y4*y5*y6^4 - 37*y4*y6^5 + 4*y5^4*y6^2 + 28*y5^3*y6^3 + 37*y5^2*y6^4 + 2*y5*y6^5 - 13*y6^6 - 8*y3*y4*y5*y6^3 + 3*y3*y4*y6^4 - y3*y5^4*y6 + 11*y3*y5^3*y6^2 - 9*y3*y5^2*y6^3 - 29*y3*y5*y6^4 + 17*y3*y6^5 + 4*y4^3*y6^3 + y4^2*y5*y6^3 + 18*y4^2*y6^4 - 11*y4*y5^3*y6^2 + 6*y4*y5^2*y6^3 - 12*y4*y5*y6^4 + 31*y4*y6^5 - y5^5*y6 + 5*y5^4*y6^2 - 5*y5^3*y6^3 - 30*y5^2*y6^4 - 23*y5*y6^5 + 17*y6^6 - y3*y4*y5^2 + y3*y4*y5*y6 - y3*y4*y6^2 - y3*y5^2*y6 - y3*y5*y6^2 + y3*y6^3 + y4^2*y5*y6 + y4*y5^2*y6 + y4*y6^3 - y5^3*y6 - 2*y5^2*y6^2 - y5*y6^3 + y6^4 - -y3*y4^2 + y3*y4*y5 - y3*y5*y6 + y3*y6^2 - y4^2*y5 + y4^2*y6 - y4*y5*y6 + 2*y4*y6^2 - y5^2*y6 - y5*y6^2 + y6^3 - -y3^2 - y3*y5 - 2*y3*y6 + y4*y5 - y4*y6 - y6^2 - y2 + y3 + y4 + y5 + y6 - -y1^5 + 2*y3*y4*y5*y6^2 - y3*y4*y6^3 - 2*y3*y5*y6^3 + y3*y6^4 + y4^2*y5*y6^2 + 2*y4*y5^2*y6^2 - y4*y5*y6^3 + y4*y6^4 - y5^2*y6^3 - 2*y5*y6^4 + y6^5] - @test_skip computed == expected - end + nuMin = tropical_semiring_map(QQ,2) + nuMax = tropical_semiring_map(QQ,2,max) + @test issetequal(groebner_basis(I,nuMin,w),[x^2-8*x*y,x+y]) # padic, min + @test issetequal(groebner_basis(I,nuMax,w),[y^2,x+y]) # padic, max - @testset "Katsura5Homogenized" begin - computed = groebner_basis(Katsura5Homogenized, val_t, w, complete_reduction=true) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [ - 385435641777613426263048919265966712483675516854427965194240000000*y2^3*y6 + 4135045376698027032593847788439386368521610555019038881218560000000*y2^2*y6^2 + 1738833261257008894611720726225458413088737749267372121784320000000*y2*y4*y6^2 + 1554656250035953161916869359591442638089287779192337145528320000000*y2*y5*y6^2 + 9330396742388670640533153190247641819519823377066585478922240000000*y2*y6^3 - 10272478123889389879949343495728028521570478134402419009781760000000*y3*y5^2*y6 + 47663541346347460286681181691322849380438581498432326142525440000000*y3*y5*y6^2 + 7452121256104298278474197596960198515047108997276507685519360000000*y3*y6^3 + 1873644445828814024271541700542599555216947863201485873479680000000*y4*y5^2*y6 - 2546752868456702449437129706716141832102220915684963411558400000000*y4*y5*y6^2 + 5957476902730373507609402061282972462141168008911509971271680000000*y4*y6^3 - 1416874811930583029400293267858643091265999830480712714158080000000*y5^4 + 3715308097339243573339884932566783885688326494604971453972480000000*y5^3*y6 - 1792308470931191723821329883138907039552450882197250774138880000000*y5^2*y6^2 - 2742810893812018193559001543012791225881982224870041106513920000000*y5*y6^3 - 13850877760864311099390049897952994900525109448940052325335040000000*y6^4 - -2394474132558509458375199684959910415842642074908308086097306719543373856612978524160000000000*y2^3*y6 - 28913630296774407553406003842515253129469688548563208649393846070267318592904772976640000000000*y2^2*y6^2 - 18241883684890371661464853499724248303159798589133366216892929306369658313036382863360000000000*y2*y4*y6^2 - 21026623954083746949492833752981019530022278009474158926779002727565701376008991539200000000000*y2*y5*y6^2 - 82518598006609305190769323882675778925403747550515120918313182591303916842366449745920000000000*y2*y6^3 + 40901390625217874731385600287702649062706936998404917836531301711830956429102148485120000000000*y3*y5^2*y6 - 359010909518282227121457881044564393024248632811326507396640255372485872528567597793280000000000*y3*y5*y6^2 - 44303295947694293657004024230359107153507763848731965300315889917035871725387660656640000000000*y3*y6^3 - 17505941981327151467023563550408125540215413706189398751406529004466495451700983234560000000000*y4*y5^3 - 22636225138445342216584534398160893390638978244073860423679285210923879022865342791680000000000*y4*y5^2*y6 + 7615911463147533379472866499625291863177816751109153932379370416477771165562044416000000000000*y4*y5*y6^2 - 43460415798197758356560809575271043763883524647676568782203851823274394046131674808320000000000*y4*y6^3 - 52985040408870919661241461321460456701786268840501524661262963934285998327124994293760000000000*y5^3*y6 - 15557768152645318705652706456695686891069875814985984608185961556479409635930008453120000000000*y5^2*y6^2 + 18842475252087809267866807013321641785841489630334823848244297273928164412206612480000000000000*y5*y6^3 + 113826702435942222202550527410150942470716078173986637653804335381114609291884201246720000000000*y6^4 - -4*y2*y6 - 8*y3*y5 - 4*y4^2 - 8*y4*y5 - 4*y5^2 + 4*y6^2 - -191734394642487456376728879164880889932766790137735503836043924493776962663597579772599730176000000000000*y2^3*y6 + 3034989467187885503938555391453256597172128462303916781976407609199479131855526508951985192960000000000000*y2^2*y6^2 + 7151526041855198647741077534182895823126707796690323254395804172231468349940801344665213206528000000000000*y2*y4*y6^2 + 14832495478536285699989219513444079325829557696427036621995306364091194845065370994813354115072000000000000*y2*y5*y6^2 + 26667505194196340565702212188528536566626836412633900419933577888455582460729341072320577404928000000000000*y2*y6^3 - 23378597204373809511426907740883951223327530309336766349093220217088668972913915065831906082816000000000000*y3*y5^3 + 3440152436718712181110268776513996654551813850716822819170942938420639520663211179355559428096000000000000*y3*y5^2*y6 + 64634779883736053194020859200730268741778720291314627917522856675592970397648550687043374546944000000000000*y3*y5*y6^2 + 17566137850892116937858807069618038472997415495898809329916988043406043304040089763866214400000000000000*y3*y6^3 - 19630334709750449599226595488368854173959341790821878414275533308386687452697840712018133254144000000000000*y4*y5^2*y6 + 20425905093017353575342220860551855136401394738631135488827473696872547153937816377423634104320000000000000*y4*y5*y6^2 + 7220385302230695746137484057895798533940857665434246586969078765361620039692638496539568766976000000000000*y4*y6^3 + 7565384249622216922797031028743096809550526905773699202208648410534114730183985859501901217792000000000000*y5^3*y6 - 32146032267132573996281616937401010405585270357494821073748088119433059246393364267875172352000000000000*y5^2*y6^2 + 1921032835373561908324239141133428687406997358631493788319721812426884895729824216576409206784000000000000*y5*y6^3 - 29510760266741738613264038700816912273866198084800081698073941573161284629921270001499962867712000000000000*y6^4 - -y2*y5 - 2*y3*y4 + 2*y3*y5 - 2*y3*y6 + 2*y4*y5 + 2*y5^2 + 2*y5*y6 - 8*y2*y4 + 8*y2*y5 + 16*y2*y6 + 8*y3^2 + 32*y3*y5 + 16*y3*y6 - 16*y5*y6 - 16*y6^2 - -163840*y2^2*y6 + 98304*y2*y4*y6 - 606208*y2*y5^2 + 32768*y2*y5*y6 - 294912*y2*y6^2 + 1605632*y3*y5^2 - 1933312*y3*y5*y6 - 393216*y3*y6^2 + 2031616*y4*y5^2 - 393216*y4*y5*y6 - 327680*y4*y6^2 + 1212416*y5^3 + 1835008*y5^2*y6 - 131072*y5*y6^2 + 458752*y6^3 - 36700160*y2^2*y6 - 96993280*y2*y4*y5 - 99614720*y2*y4*y6 - 259522560*y2*y5*y6 - 89128960*y2*y6^2 - 592445440*y3*y5^2 - 110100480*y3*y5*y6 + 10485760*y3*y6^2 - 377487360*y4*y5^2 + 10485760*y4*y5*y6 + 73400320*y4*y6^2 - 193986560*y5^3 - 178257920*y5^2*y6 + 262144000*y5*y6^2 + 52428800*y6^3 - -8*y2*y3 - 16*y2*y4 - 16*y2*y5 - 32*y2*y6 - 48*y3*y5 - 16*y3*y6 - 16*y4*y5 + 16*y5*y6 + 32*y6^2 - -193986560*y2^2*y5 - 251658240*y2^2*y6 + 461373440*y2*y4*y6 - 492830720*y2*y5*y6 + 167772160*y2*y6^2 - 2034237440*y3*y5^2 - 1572864000*y3*y5*y6 - 293601280*y3*y6^2 - 1845493760*y4*y5^2 + 482344960*y4*y5*y6 - 503316480*y4*y6^2 - 775946240*y5^3 - 440401920*y5^2*y6 + 1195376640*y5*y6^2 + 83886080*y6^3 - 620756992*y2^2*y4 - 268435456*y2^2*y6 + 2147483648*y2*y4*y6 - 3422552064*y2*y5*y6 - 1476395008*y2*y6^2 - 6308233216*y3*y5^2 - 7885291520*y3*y5*y6 + 1342177280*y3*y6^2 - 12314476544*y4*y5^2 + 1342177280*y4*y5*y6 - 3019898880*y4*y6^2 - 4966055936*y5^3 - 6677331968*y5^2*y6 + 3758096384*y5*y6^2 + 1744830464*y6^3 - 95482741799688119048687979168406002446421435212481615421719401049985521678742341990798980994914340686281137126568238009020724492690660513291377812412758162712269135609266409319038009433797947014909681546461043437921227143043345973631850999188719779583820406362750006774714179252708018104145308183108445591981349878292807680000000000000000000000000000000000000*y2^4*y6 + 746846522250271123001066525966945476460958320740386502610529704904460009016240142316132702333031686185298802628856651760855736336350217831930195927782304950767220497738868620014215845265472682586734470478087700062806151145266760903011433934438318320431133481516811632084121054566288598654469904290174066369306443932657254400000000000000000000000000000000000000*y2^3*y6^2 - 5562106284110011049661372556180961560688922688904866808702078988961446498149157287694359947809782052283326899998660138552153431920372201787277050804141473935350198084459562282216429563450090592694356726287427999067931419053485285064264993199094860681539254400547747699079264245729862161930482579709131221073655208227823943680000000000000000000000000000000000000*y2^2*y6^3 + 19431157297148117088459592983950778635614946764166487977807864775003296037308166895670038830155272083778620539930805443056654345753852059234379113085517022289588086720855599232190879629081536575896045032286169456808393995767539156847341886292805021446738575800617393492232165504733505346829714997570896390149140112618312171520000000000000000000000000000000000000*y2*y4*y6^3 + 11811096568572344231032493102530145898904485632191337644112607978115793523190655626110137872974769331163115875624685845721131589857875206465802647916760532562983979836528629546396778720856624582207584791810153779050595006854079558314561230574938117823266976654773850938332545507467138158672244712044241715752885753824443105280000000000000000000000000000000000000*y2*y5*y6^3 + 17022741465886953341763287712224673682594127390817852603446320282695288639513424526155861375817892259773390568173958193234938112951195990514132590166918333464352092439903791413694803943569803583912398729752986446941066109205511855067610645038782911988651931316462996676998900505614451460969473229547007190565631694083110993920000000000000000000000000000000000000*y2*y6^4 + 7222742209842936341399181739309865372173662624912859922414009727790235408287771591871493659275284879392133545241118008306018339250348299282542170839206826557276021945850054429488016064425086025737352025077625790538761147493612900657064303421623714713699656488484058263298114152854982992182235004977261489365022329941010677760000000000000000000000000000000000000*y3*y5^2*y6^2 + 30928829356974087470469535612111568738948324043613373275249780875519099517108694040381741301036057402837548482561708083535242480723097976449225050514159552365305774130997758088249692799777558542436598268086139500729581082661839466172064741928314804601721738967523112053285928888495663781759789038144631749938139231494487408640000000000000000000000000000000000000*y3*y5*y6^3 + 4529094205954541156594355273090289800208913529045483398848219762796695443377332580336067773646738360503583657866270867270735339261763932343883309863844880901904988219245733894796097150046850787958698833081079091999182225025432354466234006156590494643851719586485577822119529362664859129286315919782345451117948859194036715520000000000000000000000000000000000000*y3*y6^4 - 12119570773999752214946462499152565423131754089054341312482239183028747822833492279034871369059504577774022321446927294377764541256362068036472403758697047238915641624502429480892402963583155217212030583386984034931367378667227612485758998312460944399378421571205553745573642113684995089960353795957072769666380009882192445440000000000000000000000000000000000000*y4*y5^2*y6^2 + 12282813124142392371953144253678201863203051849819748046672114722234163038671723218685920193076957781437688475804017892425841689391586332480207550479501541534544122340714813988333413358991706259536974713257638709470141013897934213102311056325906116755977270161112718767036658332083541713703449069366233280874797448031906037760000000000000000000000000000000000000*y4*y5*y6^3 - 12358878480532252789673752976437791896965266505027677708728876571650145313318515801598350755790666638344887953467140095362736649107363253114228431552943000043086568544637278367670861877743887082402191102863706721623378022115097372443115656032403158779815415873862864960322972724265383300246844106933619690235783184189635952640000000000000000000000000000000000000*y4*y6^4 - 4468496753848290021734762207754460057776146432562775983772743145718755289772802580306682586811203907079739087944951602303728851320982771244208333452964708945880605285493875529366022339740842704671069266834880791817044117973684928500775999388221388050047815381006362285356765659906549050758800277540101000047754382294216867840000000000000000000000000000000000000*y5^3*y6^2 - 7799370758882407147038387696412991601856634009865328748933038832542026790385357831022113243079569775407798671807246308499259561446451814361254602651282810257399310466900249011763383176284691453248081295020494195956346788824159277288213154150714359926779486362691327379792202135902827153900734155304176934114901900948228014080000000000000000000000000000000000000*y5^2*y6^3 - 8755470907036947097627096884027930603909829807684882577832273659468954675202882077555080905385293951833665312383409134413148724227200834958636360129370675852247745990028286716673228992273112038425500885282897249493106808430262844214135785472482770962547224027149005136995409741186741513755738723559510083634338020043008245760000000000000000000000000000000000000*y5*y6^4 - 12302964445826901534151669661179063600812584457865853912776490399688287672059249722768433111336056234361643607930722944452661141859864667072077113102971922642481383988792364160811628234818983620819686155490107191373862068440336676879988936773315089407127630803794810616778471493703585915797605862311158481453264279666237112320000000000000000000000000000000000000*y6^5 - -y1 + y2 + 2*y3 + 2*y4 + 2*y5 + 2*y6] - @test_skip computed == expected - end + K,t = rational_function_field(GF(2),"t") + R,(x,y) = K["x","y"] + I = ideal(R,[x^2+t^3*y^2,x+y]) + nuMin = tropical_semiring_map(K,t) + nuMax = tropical_semiring_map(K,t,max) + @test issetequal(groebner_basis(I,nuMin,w),[x^2-t^3*x*y,x+y]) # tadic, min + @test issetequal(groebner_basis(I,nuMax,w),[y^2,x+y]) # tadic, max end + end diff --git a/test/TropicalGeometry/hypersurface.jl b/test/TropicalGeometry/hypersurface.jl deleted file mode 100644 index cd28f7a2a9e2..000000000000 --- a/test/TropicalGeometry/hypersurface.jl +++ /dev/null @@ -1,14 +0,0 @@ -@testset "hypersurface" begin - for addition in (max, min) - T = TropicalSemiring(addition) - R,(x,y,z) = polynomial_ring(T,3) - b = [T(10),T(3//2095), T(-5//2)] - m = [[1,0,1],[0,3,4],[1,0,7]] - f = R(b,m) - hyp = TropicalHypersurface(f) - coeffs, exps = Oscar.homogenize_and_convert_to_pm(f) - @test hyp isa TropicalHypersurface{addition} - @test coeffs == get_attribute(hyp, :polymake_bigobject).COEFFICIENTS - @test exps == matrix(ZZ, get_attribute(hyp, :polymake_bigobject).MONOMIALS) - end -end diff --git a/test/TropicalGeometry/initial.jl b/test/TropicalGeometry/initial.jl index b49ddd5187c8..89a3beb463c9 100644 --- a/test/TropicalGeometry/initial.jl +++ b/test/TropicalGeometry/initial.jl @@ -1,73 +1,34 @@ -@testset "initial" begin - Kx,(x0,x1,x2,x3,x4,x5) = polynomial_ring(QQ,6) - Cyclic5Homogenized = ideal([x1+x2+x3+x4+x5, - x1*x2+x2*x3+x3*x4+x1*x5+x4*x5, - x1*x2*x3+x2*x3*x4+x1*x2*x5+x1*x4*x5+x3*x4*x5, - x1*x2*x3*x4+x1*x2*x3*x5+x1*x2*x4*x5+x1*x3*x4*x5+x2*x3*x4*x5, - -x0^5+x1*x2*x3*x4*x5]) - Katsura5Homogenized = ideal([-x0+x1+2*x2+2*x3+2*x4+2*x5, - -x0*x1+x1^2+2*x2^2+2*x3^2+2*x4^2+2*x5^2, - -x0*x2+2*x1*x2+2*x2*x3+2*x3*x4+2*x4*x5, - x2^2-x0*x3+2*x1*x3+2*x2*x4+2*x3*x5, - 2*x2*x3-x0*x4+2*x1*x4+2*x2*x5]) - w = [0,0,0,0,0,0] - @testset "val_2" begin - val_2 = TropicalSemiringMap(QQ,2) - @testset "Cyclic5Homogenized" begin - computed = gens(initial(Cyclic5Homogenized, val_2, w)) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y2 + y3 + y4 + y5 + y6, y3^2 + y3*y5 + y4*y5 + y4*y6 + y6^2, y3*y4^2 + y3*y4*y5 + y3*y5*y6 + y3*y6^2 + y4^2*y5 + y4^2*y6 + y4*y5*y6 + y5^2*y6 + y5*y6^2 + y6^3, y3*y4*y5^2 + y3*y4*y5*y6 + y3*y4*y6^2 + y3*y5^2*y6 + y3*y5*y6^2 + y3*y6^3 + y4^2*y5*y6 + y4*y5^2*y6 + y4*y6^3 + y5^3*y6 + y5*y6^3 + y6^4, y3*y4*y5^2 + y3*y5*y6^2 + y4^3*y5 + y4^3*y6 + y4^2*y5^2 + y4*y5^2*y6 + y4*y6^3 + y5^2*y6^2, y3*y4*y5*y6^2 + y3*y5^3*y6 + y4^3*y6^2 + y4^2*y5^2*y6 + y4^2*y5*y6^2 + y4^2*y6^3 + y4*y5^3*y6 + y4*y5*y6^3 + y5^4*y6 + y5^3*y6^2, y3*y4*y6^3 + y3*y5^3*y6 + y3*y5^2*y6^2 + y3*y6^4 + y4^2*y5^3 + y4^2*y5*y6^2 + y4^2*y6^3 + y5^4*y6 + y5^3*y6^2 + y5^2*y6^3 + y5*y6^4 + y6^5, y1^5 + y3*y4*y6^3 + y3*y6^4 + y4^2*y5*y6^2 + y4*y5*y6^3 + y4*y6^4 + y5^2*y6^3 + y6^5, y3*y4*y6^4 + y3*y5^3*y6^2 + y3*y5^2*y6^3 + y3*y6^5 + y4^4*y6^2 + y4^3*y6^3 + y4^2*y5*y6^3 + y4*y6^5 + y5^2*y6^4 + y6^6, y3*y4*y6^4 + y3*y5^3*y6^2 + y3*y5^2*y6^3 + y3*y6^5 + y4^4*y6^2 + y4^2*y6^4 + y4*y5^4*y6 + y4*y5^3*y6^2 + y4*y6^5 + y5^4*y6^2 + y5^2*y6^4 + y6^6, y3*y4*y6^4 + y3*y5^4*y6 + y3*y5^3*y6^2 + y3*y5^2*y6^3 + y3*y5*y6^4 + y3*y6^5 + y4^3*y6^3 + y4^2*y6^4 + y4*y5^4*y6 + y4*y6^5 + y5^5*y6 + y5^3*y6^3 + y5*y6^5 + y6^6, y3*y4*y5*y6^4 + y3*y5^3*y6^3 + y4^2*y5*y6^4 + y4*y5^2*y6^4 + y4*y5*y6^5 + y5^5*y6^2 + y5^4*y6^3 + y5^3*y6^4] - @test computed == expected - end - @testset "Katsura5Homogenized" begin - computed = gens(initial(Katsura5Homogenized, val_2, w)) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y1 + y2, y2*y6 + y4^2 + y5^2 + y6^2, y2*y5, y2*y4 + y2*y5 + y3^2, y2*y3, y2*y5^2, y2*y4*y5 + y2*y5*y6, y2^2*y5, y2^2*y4 + y2*y5^2, y2^3*y6 + y2^2*y6^2, y2*y5^2*y6, y2^2*y6^2 + y2*y4*y6^2 + y2*y5^2*y6 + y2*y5*y6^2 + y2*y6^3 + y3*y5^3 + y3*y5*y6^2 + y4*y5^2*y6 + y5^4 + y5^2*y6^2, y2*y5^3 + y2*y5^2*y6, y2^4*y6 + y2^3*y6^2 + y2*y5^2*y6^2, y2*y5^2*y6^2] - @test computed == expected - end - end +@testset "src/TropicalGeometry/initial.jl" begin - @testset "val_3" begin - val_3 = TropicalSemiringMap(QQ,3) - @testset "Cyclic5Homogenized" begin - computed = gens(initial(Cyclic5Homogenized, val_3, w)) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y2 + y3 + y4 + y5 + y6, y3^2 + y3*y5 + 2*y3*y6 + 2*y4*y5 + y4*y6 + y6^2, y3*y4^2 + 2*y3*y4*y5 + y3*y5*y6 + 2*y3*y6^2 + y4^2*y5 + 2*y4^2*y6 + y4*y5*y6 + y4*y6^2 + y5^2*y6 + y5*y6^2 + 2*y6^3, y3*y4*y5^2 + y3*y4*y5*y6 + 2*y3*y4*y6^2 + 2*y3*y5^2*y6 + 2*y3*y5*y6^2 + y3*y6^3 + y4^2*y5*y6 + y4*y5^2*y6 + y4*y6^3 + 2*y5^3*y6 + y5^2*y6^2 + 2*y5*y6^3 + y6^4, y3*y4*y5^2 + y3*y4*y6^2 + y3*y6^3 + y4^3*y5 + 2*y4^3*y6 + 2*y4^2*y5^2 + y4^2*y5*y6 + 2*y4^2*y6^2 + y4*y5^2*y6 + 2*y4*y5*y6^2 + y4*y6^3 + 2*y5*y6^3 + y6^4, 2*y3*y4*y5*y6^2 + y3*y4*y6^3 + 2*y3*y5^3*y6 + y3*y5^2*y6^2 + y3*y5*y6^3 + 2*y3*y6^4 + y4^3*y6^2 + y4^2*y5^2*y6 + 2*y4^2*y5*y6^2 + 2*y4^2*y6^3 + y4*y5^2*y6^2 + 2*y5^4*y6 + y5^3*y6^2 + 2*y6^5, y3*y4*y5*y6^2 + 2*y3*y5^3*y6 + 2*y3*y5^2*y6^2 + 2*y3*y5*y6^3 + 2*y3*y6^4 + y4^2*y5^3 + 2*y4^2*y5*y6^2 + y4^2*y6^3 + y4*y5^2*y6^2 + y4*y5*y6^3 + 2*y5^4*y6 + 2*y5^2*y6^3 + 2*y6^5, y1^5 + y3*y4*y5*y6^2 + y3*y4*y6^3 + 2*y3*y5*y6^3 + 2*y3*y6^4 + 2*y4^2*y5*y6^2 + y4*y5^2*y6^2 + y4*y5*y6^3 + 2*y4*y6^4 + y5^2*y6^3 + 2*y5*y6^4 + 2*y6^5, 2*y3*y4*y5*y6^3 + y3*y6^5 + y4^4*y6^2 + 2*y4^2*y6^4 + 2*y4*y5^3*y6^2 + 2*y4*y5^2*y6^3 + 2*y4*y5*y6^4 + y4*y6^5 + 2*y5^4*y6^2 + 2*y5^3*y6^3 + 2*y5^2*y6^4 + y5*y6^5 + y6^6, y3*y4*y5*y6^3 + 2*y3*y4*y6^4 + y3*y5^3*y6^2 + y3*y5^2*y6^3 + y3*y5*y6^4 + 2*y4^4*y6^2 + y4^3*y6^3 + 2*y4^2*y5*y6^3 + y4*y5^4*y6 + y4*y5^3*y6^2 + y4*y5^2*y6^3 + y4*y6^5 + y5^4*y6^2 + y5^3*y6^3 + 2*y5^2*y6^4 + 2*y5*y6^5, y3*y4*y5*y6^3 + y3*y5^4*y6 + y3*y5^3*y6^2 + 2*y3*y5*y6^4 + y3*y6^5 + 2*y4^3*y6^3 + 2*y4^2*y5*y6^3 + 2*y4*y5^3*y6^2 + 2*y4*y6^5 + y5^5*y6 + y5^4*y6^2 + 2*y5^3*y6^3 + 2*y5*y6^5 + y6^6, y3*y4*y5*y6^4 + 2*y3*y5^3*y6^3 + y3*y5^2*y6^4 + y3*y5*y6^5 + y3*y6^6 + 2*y4^2*y5*y6^4 + 2*y4^2*y6^5 + y4*y5^3*y6^3 + y4*y5*y6^5 + y5^5*y6^2 + y5^3*y6^4 + y6^7] - @test computed == expected - end - @testset "Katsura5Homogenized" begin - computed = gens(initial(Katsura5Homogenized, val_3, w)) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y1 + 2*y2 + y3 + y4 + y5 + y6, y2*y6 + 2*y3*y5 + y4^2 + 2*y4*y5 + y5^2 + 2*y6^2, y2*y5 + 2*y3*y4 + y3*y5 + 2*y3*y6 + y4*y5 + y5^2 + y5*y6, y2*y4 + y2*y5 + y3^2 + 2*y3*y6 + y4^2 + 2*y4*y5 + y5^2 + y5*y6, y2*y3 + 2*y2*y4 + 2*y2*y5 + y3*y5 + 2*y3*y6 + 2*y4^2 + 2*y5^2 + y5*y6, y2^2*y6 + y2*y5^2 + y2*y5*y6 + y3*y5^2 + y3*y5*y6 + 2*y4*y5^2 + 2*y4*y6^2 + y5^3 + 2*y5^2*y6 + 2*y5*y6^2 + 2*y6^3, y2^2*y6 + y2*y4*y5 + 2*y2*y4*y6 + y2*y6^2 + y3*y5^2 + 2*y3*y6^2 + 2*y4*y5*y6 + 2*y4*y6^2 + 2*y5^3 + 2*y5^2*y6 + 2*y5*y6^2 + y6^3, y2^2*y5 + y2^2*y6 + 2*y2*y4*y6 + y2*y5^2 + 2*y2*y5*y6 + y2*y6^2 + 2*y3*y5^2 + y3*y5*y6 + 2*y3*y6^2 + y4*y5*y6 + 2*y4*y6^2 + 2*y5^3 + 2*y5^2*y6 + 2*y5*y6^2 + y6^3, y2^2*y4 + 2*y2^2*y6 + 2*y2*y4*y6 + 2*y2*y6^2 + 2*y3*y5^2 + y3*y5*y6 + 2*y3*y6^2 + y4*y5^2 + 2*y4*y5*y6 + y5^3 + y5^2*y6 + 2*y5*y6^2 + 2*y6^3, 2*y2^3*y6 + y2^2*y6^2 + 2*y2*y4*y6^2 + 2*y2*y5^2*y6 + 2*y2*y5*y6^2 + 2*y3*y5^2*y6 + y3*y6^3 + 2*y4*y6^3 + 2*y5^3*y6 + y5^2*y6^2 + 2*y5*y6^3, 2*y2^2*y6^2 + 2*y2*y4*y6^2 + y2*y5^2*y6 + y2*y6^3 + 2*y3*y5*y6^2 + 2*y3*y6^3 + 2*y4*y5^3 + y4*y5^2*y6 + 2*y4*y5*y6^2 + y4*y6^3 + 2*y5^2*y6^2 + 2*y5*y6^3, y2^2*y6^2 + 2*y2*y4*y6^2 + y2*y5^2*y6 + 2*y2*y5*y6^2 + y2*y6^3 + y3*y5^3 + y3*y5^2*y6 + 2*y3*y6^3 + 2*y4*y6^3 + 2*y5^4 + 2*y5^3*y6 + y5^2*y6^2 + y6^4, 2*y2^2*y6^2 + y2*y4*y6^2 + y2*y5^3 + y2*y5*y6^2 + 2*y2*y6^3 + y3*y5^3 + 2*y3*y5^2*y6 + 2*y3*y5*y6^2 + y3*y6^3 + 2*y4*y5^3 + y4*y5*y6^2 + y4*y6^3 + y5^4 + 2*y6^4, y2^4*y6 + y2^3*y6^2 + 2*y2*y4*y6^3 + y2*y5^2*y6^2 + 2*y2*y5*y6^3 + 2*y3*y5*y6^3 + 2*y4*y5^2*y6^2 + y4*y6^4 + 2*y5^4*y6 + y5^3*y6^2 + y5*y6^4 + y6^5, 2*y2*y4*y6^3 + y2*y6^4 + 2*y3*y5^2*y6^2 + 2*y3*y5*y6^3 + 2*y3*y6^4 + y4*y5*y6^3 + 2*y5^4*y6 + 2*y5^2*y6^3 + 2*y5*y6^4 + 2*y6^5] - @test computed == expected - end - end - @testset "val_t" begin - Kt,t = rational_function_field(QQ,"t") - Ktx,(x0,x1,x2,x3,x4,x5) = polynomial_ring(Kt,6) - Cyclic5Homogenized_Kt = ideal([change_coefficient_ring(Kt,f) for f in gens(Cyclic5Homogenized)]) - Katsura5Homogenized_Kt = ideal([change_coefficient_ring(Kt,f) for f in gens(Katsura5Homogenized)]) - val_t = TropicalSemiringMap(Kt,t) - @testset "Cyclic5Homogenized_Kt" begin - computed = gens(initial(Cyclic5Homogenized_Kt, val_t, w)) - # Apparently the Groebner basis lives in a different ring, so we have - # to hack around this... - computed_ring = parent(computed[1]) - (y1, y2, y3, y4, y5, y6) = gens(computed_ring) - expected = [y2 + y3 + y4 + y5 + y6, y2*y6 - y3^2 - y3*y5 - y3*y6 + y4*y5 + y5*y6, -y2*y3*y6 + y2*y4*y6 - y2*y5*y6 + y3*y4^2 - y3*y4*y5 + y4^2*y5, -y2*y3*y4*y6 - y2*y4*y5*y6 + y2*y5^2*y6 + y3*y4*y5^2 - y3*y4*y5*y6 + y4*y5^2*y6, -y2*y3^2*y6 + y2*y3*y4*y6 - y2*y3*y5*y6 + y2*y4^2*y6 - y2*y4*y5*y6 - y3*y4^2*y6 + y3*y4*y5^2 + y3*y4*y5*y6 + y4^3*y5 - y4^2*y5^2 + y4^2*y5*y6 - y4*y5^2*y6, 2*y2*y3^2*y6^2 - 2*y2*y3*y4*y6^2 + 4*y2*y3*y5*y6^2 - y2*y4^2*y6^2 - y2*y4*y5*y6^2 + y2*y5^3*y6 + 2*y2*y5^2*y6^2 + y3*y4^2*y6^2 - 2*y3*y4*y5*y6^2 + y4^2*y5^2*y6 + y4^2*y5*y6^2 - 2*y4*y5^3*y6 + 3*y4*y5^2*y6^2 - 2*y5^3*y6^2, y2*y3^2*y4*y6 + 2*y2*y3*y4*y5*y6 - y2*y3*y5^2*y6 - y2*y5^3*y6 + y3^2*y4*y5*y6 + y3*y4*y5^2*y6 - y4^2*y5^3 - 2*y4*y5^3*y6, -y1^5 + y2*y3*y4*y5*y6, -3*y2*y3^2*y5*y6^2 + 2*y2*y3^2*y6^3 + 2*y2*y3*y4*y5*y6^2 + 2*y2*y3*y4*y6^3 - y2*y3*y5^2*y6^2 - 2*y2*y4^2*y5*y6^2 - 6*y2*y4^2*y6^3 + 4*y2*y4*y5^2*y6^2 + 3*y2*y4*y5*y6^3 + y2*y5^3*y6^2 + y3^2*y4*y5*y6^2 - 2*y3^2*y4*y6^3 + 2*y3^2*y5*y6^3 + 4*y3*y4^2*y5*y6^2 + 4*y3*y4^2*y6^3 - 5*y3*y4*y5^2*y6^2 - y3*y4*y5*y6^3 + 2*y3*y5^3*y6^2 + y4^4*y6^2 - 4*y4^3*y5*y6^2 + y4^3*y6^3 + 2*y4^2*y5^2*y6^2 - 3*y4^2*y5*y6^3 + y5^4*y6^2, y2*y3^2*y5*y6^2 - 2*y2*y3*y4^2*y6^2 - 3*y2*y3*y4*y5*y6^2 + 3*y2*y3*y5^2*y6^2 - y2*y4^3*y6^2 - 2*y2*y4^2*y5*y6^2 + y2*y4*y5^2*y6^2 + 4*y2*y5^3*y6^2 - 2*y3^2*y4*y5*y6^2 + y3*y4^3*y6^2 - y3*y4^2*y5*y6^2 - 5*y3*y4*y5^2*y6^2 + y4^3*y5*y6^2 + 2*y4^2*y5^2*y6^2 - y4*y5^4*y6 + 4*y4*y5^3*y6^2, -y2*y3^2*y4*y6^2 - 2*y2*y3^2*y5*y6^2 - 3*y2*y3*y5^2*y6^2 + y2*y4^2*y5*y6^2 + y2*y4*y5^2*y6^2 - y2*y5^3*y6^2 - y3^2*y4*y5*y6^2 - y3*y4^2*y5*y6^2 + y3*y4*y5^2*y6^2 + y3*y5^4*y6 - y4^2*y5^2*y6^2 + 3*y4*y5^4*y6 - y4*y5^3*y6^2 + y5^5*y6 + 3*y5^4*y6^2, -4*y2*y3^2*y5*y6^3 + 13*y2*y3*y4^2*y6^3 + 16*y2*y3*y4*y5*y6^3 - 11*y2*y3*y5^2*y6^3 + 6*y2*y4^3*y6^3 + 9*y2*y4^2*y5*y6^3 - 12*y2*y4*y5^2*y6^3 - 16*y2*y5^3*y6^3 + 11*y3^2*y4*y5*y6^3 + 2*y3^2*y5^2*y6^3 - 6*y3*y4^3*y6^3 + 10*y3*y4^2*y5*y6^3 + 23*y3*y4*y5^2*y6^3 + 3*y3*y5^3*y6^3 - 7*y4^3*y5*y6^3 - 12*y4^2*y5^2*y6^3 - 21*y4*y5^3*y6^3 - y5^5*y6^2 - 3*y5^4*y6^3] - @test_broken computed == expected - end + @testset "initial(::MPolyRingElem,::TropicalSemiringMap,::Vector)" begin + R,(x,y) = QQ["x","y"] + f = x^2+y^2+2*x+2*y + w = [-1,-1] + nuMin = tropical_semiring_map(QQ) + nuMax = tropical_semiring_map(QQ,max) + @test initial(f,nuMin,w) == x^2+y^2 # trivial, min + @test initial(f,nuMax,w) == 2*x+2*y # trivial, max + + nuMin = tropical_semiring_map(QQ,2) + nuMax = tropical_semiring_map(QQ,2,max) + S,(x,y) = GF(2)["x","y"] + @test initial(f,nuMin,w) == x^2+y^2 # padic, min + @test initial(f,nuMax,w) == x^2+y^2+x+y # tadic, max + + K,t = rational_function_field(GF(2),"t") + R,(x,y) = K["x","y"] + f = x^2+y^2+t*x+t*y + w = [-1,-1] + nuMin = tropical_semiring_map(K,t) + nuMax = tropical_semiring_map(K,t,max) + S,(x,y) = GF(2)["x","y"] + @test initial(f,nuMin,w) == x^2+y^2 # tadic, min + @test initial(f,nuMax,w) == x^2+y^2+x+y # tadic, max end + + # no tests for initial(::MPolyIdeal,::TropicalSemiringMap,::Vector), + # function is a simple composition of + # - initial(::MPolyRingElem,::TropicalSemiringMap,::Vector) and + # - groebner_basis(I::MPolyIdeal, nu::TropicalSemiringMap, w::Vector) + end diff --git a/test/TropicalGeometry/matrix.jl b/test/TropicalGeometry/matrix.jl new file mode 100644 index 000000000000..87b345fa355f --- /dev/null +++ b/test/TropicalGeometry/matrix.jl @@ -0,0 +1,11 @@ +@testset "src/TropicalGeometry/matrix.jl" begin + + for minOrMax in (min,max) + T = tropical_semiring(minOrMax) + @testset "det(A::Generic.MatSpaceElem{<:TropicalSemiringElem})" begin + A = matrix(T,[1 2; 3 5]) + @test det(A) == (minOrMax==min ? T(5) : T(6)) + end + end + +end diff --git a/test/TropicalGeometry/poly.jl b/test/TropicalGeometry/poly.jl new file mode 100644 index 000000000000..d2565233588f --- /dev/null +++ b/test/TropicalGeometry/poly.jl @@ -0,0 +1,11 @@ +@testset "src/TropicalGeometry/poly.jl" begin + @testset "tropical_polynomial(::MPolyRingElem,::TropicalSemiringMap)" begin + K,t = rational_function_field(GF(2),"t") + nu = tropical_semiring_map(K,t) + R,(x,y) = K["x","y"] + f = x+t*y+t^2 + tropf = tropical_polynomial(f,nu) + @test issetequal(coefficients(tropf),tropical_semiring(nu).([0,1,2])) + @test issetequal(exponents(tropf),[[1,0],[0,1],[0,0]]) + end +end diff --git a/test/TropicalGeometry/semiring.jl b/test/TropicalGeometry/semiring.jl new file mode 100644 index 000000000000..df52e2595409 --- /dev/null +++ b/test/TropicalGeometry/semiring.jl @@ -0,0 +1,27 @@ +@testset "src/TropicalGeometry/semiring.jl" begin + + @testset "constructors and convention" begin + @test convention(tropical_semiring())==min + @test convention(tropical_semiring(min))==min + @test convention(tropical_semiring(max))==max + end + + for minOrMax in (min,max) + T = tropical_semiring(minOrMax) + @testset "conversions" begin + for K in (QQ,ZZ,Int) + @test T(K(0)) == one(T) + @test K(one(T)) == 0 + @test K(T(1)) == 1 + @test K(T(1),preserve_ordering=true) == (minOrMax==min ? 1 : -1) + end + end + + @testset "arithmetics" begin + @test zero(T)+one(T) == one(T) + @test zero(T)*one(T) == zero(T) + @test T(0)+T(1) == (minOrMax==min ? T(0) : T(1)) + end + end + +end diff --git a/test/TropicalGeometry/semiring_map.jl b/test/TropicalGeometry/semiring_map.jl new file mode 100644 index 000000000000..3d6005fc73cf --- /dev/null +++ b/test/TropicalGeometry/semiring_map.jl @@ -0,0 +1,32 @@ +@testset "src/TropicalGeometry/semiringMaps.jl" begin + + ### + # constructing all possible semiring maps + # and performing basic sanity checks + ### + for minOrMax in (min,max) + T = tropical_semiring(minOrMax) + + @testset "trivial valuation" begin + nu = tropical_semiring_map(GF(2),minOrMax) + @test nu(0)==zero(T) + @test nu(1)==one(T) + end + + @testset "p-adic valuation" begin + nu = tropical_semiring_map(QQ,2,minOrMax) + @test nu(0)==zero(T) + @test nu(1+2)==one(T) + @test nu(2+4)==(minOrMax==min ? T(1) : T(-1)) + end + + @testset "t-adic valuation" begin + K,t = rational_function_field(GF(2),"t") + nu = tropical_semiring_map(K,t,minOrMax) + @test nu(0)==zero(T) + @test nu(1+t)==one(T) + @test nu(t+t^2)==(minOrMax==min ? T(1) : T(-1)) + end + end + +end diff --git a/test/TropicalGeometry/variety.jl b/test/TropicalGeometry/variety.jl new file mode 100644 index 000000000000..a7d3a5776d4a --- /dev/null +++ b/test/TropicalGeometry/variety.jl @@ -0,0 +1,44 @@ +@testset "src/TropicalGeometry/{variety,hypersurface,curve,linear_space}.jl" begin + + # constructing various tropicalizations two ways + # and comparing their results + @testset "hypersurface and linear spaces" begin + R,(x,y,z) = QQ["x","y","z"] + f = x+2*y+4*z + nu = tropical_semiring_map(QQ,2) + TropH = tropical_hypersurface(f,nu) + TropL = tropical_linear_space(ideal(R,f),nu) + @test issetequal(maximal_polyhedra(TropH),maximal_polyhedra(TropL)) + nu = tropical_semiring_map(QQ,2,max) + TropH = tropical_hypersurface(f,nu) + TropL = tropical_linear_space(ideal(R,f),nu) + @test issetequal(maximal_polyhedra(TropH),maximal_polyhedra(TropL)) + end + + @testset "binomial ideals and linear spaces" begin + R,(x,y,z,w) = QQ["x","y","z","w"] + I = ideal(R,[x+2*y,z+4*w]) + nu = tropical_semiring_map(QQ,2) + TropV = first(tropical_variety(I,nu)) + TropL = tropical_linear_space(I,nu) + @test issetequal(maximal_polyhedra(TropV),maximal_polyhedra(TropL)) + nu = tropical_semiring_map(QQ,2,max) + TropV = first(tropical_variety(I,nu)) + TropL = tropical_linear_space(I,nu) + @test issetequal(maximal_polyhedra(TropV),maximal_polyhedra(TropL)) + end + + @testset "hypersurface and binomial ideals" begin + R,(x,y,z) = QQ["x","y","z"] + f = x*y*z+2 + nu = tropical_semiring_map(QQ,2) + TropH = tropical_hypersurface(f,nu) + TropV = first(tropical_variety(ideal(R,f),nu)) + @test issetequal(maximal_polyhedra(TropH),maximal_polyhedra(TropV)) + nu = tropical_semiring_map(QQ,2,max) + TropV = first(tropical_variety(ideal(R,f),nu)) + TropH = tropical_hypersurface(f,nu) + @test issetequal(maximal_polyhedra(TropH),maximal_polyhedra(TropV)) + end + +end