Skip to content

Commit

Permalink
gh-38291: Implement a custom class for tropical polynomials
Browse files Browse the repository at this point in the history
    
<!-- ^ Please provide a concise and informative title. -->
<!-- ^ Don't put issue numbers in the title, do this in the PR
description below. -->
<!-- ^ For example, instead of "Fixes #12345" use "Introduce new method
to calculate 1 + 2". -->
<!-- v Describe your changes below in detail. -->
<!-- v Why is this change required? What problem does it solve? -->
<!-- v If this PR resolves an open issue, please link to it here. For
example, "Fixes #12345". -->

This pull request introduces some new class for handling tropical
polynomials and its related functionality.

### Summary of changes:

1. Added a new class: `TropicalPolynomialSemiring` as a parent of
univariate tropical polynomials and incorporated this class into the
`PolynomialRing` constructor.
2. Added a new class: `TropicalPolynomial` as an element of univariate
tropical polynomials, which include methods like:

- `roots`: return the list of tropical roots, counted with multiplicity
- `splif_form`: return the tropical polynomial which has the same roots,
but which can be reduced to its linear factors
- `factor`: perform factorization
- `piecewise_function`: return the tropical polynomial function
- `plot`: plotting the tropical polynomial function

3. Added a new class: `TropicalMPolynomialSemiring` as a parent of
multivariate tropical polynomials and incorporated this class into the
`PolynomialRing` constructor.
4. Added a new class: `TropicalMPolynomial` as an element of
multivariate tropical polynomials, which include methods like:

- `plot3d`: return the 3d plot of tropical polynomials in two variables
- `tropical_variety`: find tropical variety for any multivariate
tropical polynomials

5. Added a new class: `TropicalVariety` and its subclass `TropicalCurve`
and `TropicalSurface` to handle the result of `tropical_variety()` of
multivariate tropical polynomials. The `TropicalVariety` include methods
like:

- `__init__`: calculation of tropical variety
- `dimension`: return the dimension of tropical variety
- `number_of_components`: return the number of components that make up
this tropical variety
- `components`: show all the components of this tropical variety
- `_components_intersection`: return the intersection of three or more
components

6. Implement the `plot` method inside the two subclasses,
`TropicalCurve` and `TropicalSurface`.

Fixes #37962.

CC: @tscrim

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [ ] The title is concise and informative.
- [ ] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation and checked the documentation
preview.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - #12345: short description why this is a dependency -->
<!-- - #34567: ... -->
    
URL: #38291
Reported by: Verrel Rievaldo Wijaya
Reviewer(s): Travis Scrimshaw, Verrel Rievaldo Wijaya
  • Loading branch information
Release Manager committed Aug 27, 2024
2 parents 8ba0b84 + dceaa1e commit e9b9d32
Show file tree
Hide file tree
Showing 10 changed files with 2,920 additions and 13 deletions.
10 changes: 10 additions & 0 deletions src/doc/en/reference/polynomial_rings/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ Infinite Polynomial Rings
sage/rings/polynomial/symmetric_ideal
sage/rings/polynomial/symmetric_reduction

Tropical Polynomials
--------------------

.. toctree::
:maxdepth: 1

sage/rings/semirings/tropical_polynomial
sage/rings/semirings/tropical_mpolynomial
sage/rings/semirings/tropical_variety

Boolean Polynomials
-------------------

Expand Down
7 changes: 7 additions & 0 deletions src/doc/en/reference/references/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,9 @@ REFERENCES:
.. [BrHu2019] Petter Brändén, June Huh. *Lorentzian polynomials*.
Ann. Math. (2) 192, No. 3, 821-891 (2020).
:arxiv:`1902.03719`, :doi:`10.4007/annals.2020.192.3.4`.
.. [Bru2014] Erwan Brugalle and Kristin Shaw. *A bit of tropical geometry*.
Amer. Math. Monthly, 121(7):563-589, 2014.
.. [BHNR2004] \S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the
Palindromic Complexity of Infinite Words,
Expand Down Expand Up @@ -2612,6 +2615,10 @@ REFERENCES:
Wehler K3 Surfaces over finite fields*. New Zealand Journal
of Mathematics 45 (2015), 19–31.
.. [Fil2017] Ivana Filipan, *An Invitation to Combinatorial Tropical Geometry*.
Conference: 1st Croatian Combinatorial Days. 2017.
:doi:`10.5592/CO/CCD.2016.05`.
.. [FIV2012] \H. Fournier, A. Ismail, and A. Vigneron. *Computing the Gromov
hyperbolicity of a discrete metric space*. 2012.
:arxiv:`1210.3323`.
Expand Down
4 changes: 2 additions & 2 deletions src/sage/rings/polynomial/multi_polynomial.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2665,7 +2665,7 @@ cdef class MPolynomial(CommutativePolynomial):

if gens:
# substituting all variables (in a polynomial ring with variables) with 0
d = {str(gen): 0 for gen in gens}
d = {str(gen): self.base_ring().zero() for gen in gens}
tester.assertEqual(self.subs(**d).parent(), self.parent().base_ring())

# substituting all variables (in a polynomial ring with variables)
Expand All @@ -2678,7 +2678,7 @@ cdef class MPolynomial(CommutativePolynomial):

if len(gens) > 1:
# substituting one variable (in a polynomial ring with variables) with 0
d = {str(gens[0]): 0}
d = {str(gens[0]): self.base_ring().zero()}
tester.assertEqual(self.subs(**d).parent(), self.parent())

# test error checking: partial substitution by elements
Expand Down
9 changes: 7 additions & 2 deletions src/sage/rings/polynomial/multi_polynomial_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,14 @@ def __call__(self, *x, **kwds):
K = x[0].parent()
except AttributeError:
K = self.parent().base_ring()
y = K(0)
try:
y = K.zero()
one = K.one()
except (AttributeError, RuntimeError):
y = K(0)
one = K(1)
for m, c in self.element().dict().items():
y += c * prod(v ** e for v, e in zip(x, m) if e)
y += c * prod((v ** e for v, e in zip(x, m) if e), one)
return y

def _richcmp_(self, right, op):
Expand Down
8 changes: 6 additions & 2 deletions src/sage/rings/polynomial/polydict.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,9 @@ cdef class PolyDict:
ring = self.__repn[E[0]].parent()
pos_one = ring.one()
neg_one = -pos_one
except AttributeError:
except (AttributeError, ArithmeticError):
# AritchmeticError occurs when self.__repn[E[0]] is a tropical
# semiring element
# probably self.__repn[E[0]] is not a ring element
pos_one = 1
neg_one = -1
Expand Down Expand Up @@ -901,7 +903,9 @@ cdef class PolyDict:
ring = self.__repn[E[0]].parent()
pos_one = ring.one()
neg_one = -pos_one
except AttributeError:
except (AttributeError, ArithmeticError):
# AritchmeticError occurs when self.__repn[E[0]] is a tropical
# semiring element
# probably self.__repn[E[0]] is not a ring element
pos_one = 1
neg_one = -1
Expand Down
2 changes: 1 addition & 1 deletion src/sage/rings/polynomial/polynomial_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -6051,7 +6051,7 @@ cdef class Polynomial(CommutativePolynomial):
- Naqi Jaffery (2006-01-24): examples
"""
return not self.is_zero() and self[self.degree()] == 1
return not self.is_zero() and self[self.degree()] == self.base_ring().one()

def is_unit(self):
r"""
Expand Down
22 changes: 16 additions & 6 deletions src/sage/rings/polynomial/polynomial_ring_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ def PolynomialRing(base_ring, *args, **kwds):
sage: PolynomialRing(4)
Traceback (most recent call last):
...
TypeError: base_ring 4 must be a ring
TypeError: base_ring 4 must be a ring or the tropical semiring
sage: PolynomialRing(QQ, -1)
Traceback (most recent call last):
...
Expand Down Expand Up @@ -622,8 +622,9 @@ def PolynomialRing(base_ring, *args, **kwds):
sage: R.<x,y> = PolynomialRing(RIF,2)
sage: TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive'])
"""
if base_ring not in Rings():
raise TypeError("base_ring {!r} must be a ring".format(base_ring))
from sage.rings.semirings.tropical_semiring import TropicalSemiring
if base_ring not in Rings() and not isinstance(base_ring, TropicalSemiring):
raise TypeError("base_ring {!r} must be a ring or the tropical semiring".format(base_ring))

n = -1 # Unknown number of variables
names = None # Unknown variable names
Expand Down Expand Up @@ -792,7 +793,11 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non

# Generic implementations
if constructor is None:
if base_ring not in _CommutativeRings:
from sage.rings.semirings.tropical_semiring import TropicalSemiring
if isinstance(base_ring, TropicalSemiring):
from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring
constructor = TropicalPolynomialSemiring
elif base_ring not in _CommutativeRings:
constructor = polynomial_ring.PolynomialRing_general
elif base_ring in _CompleteDiscreteValuationRings:
constructor = polynomial_ring.PolynomialRing_cdvr
Expand All @@ -804,6 +809,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non
constructor = polynomial_ring.PolynomialRing_integral_domain
else:
constructor = polynomial_ring.PolynomialRing_commutative

implementation_names = constructor._implementation_names(implementation, base_ring, sparse)

# Only use names which are not supported by the specialized class.
Expand Down Expand Up @@ -861,7 +867,11 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat

if R is None and implementation == "generic":
from . import multi_polynomial_ring
if base_ring in _Domains:
from sage.rings.semirings.tropical_semiring import TropicalSemiring
if isinstance(base_ring, TropicalSemiring):
from sage.rings.semirings.tropical_mpolynomial import TropicalMPolynomialSemiring
constructor = TropicalMPolynomialSemiring
elif base_ring in _Domains:
constructor = multi_polynomial_ring.MPolynomialRing_polydict_domain
else:
constructor = multi_polynomial_ring.MPolynomialRing_polydict
Expand Down Expand Up @@ -1024,4 +1034,4 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order='lex'):

############################################################################
# END (Factory function for making polynomial rings)
############################################################################
############################################################################
Loading

0 comments on commit e9b9d32

Please sign in to comment.