Last active
May 13, 2025 16:46
-
-
Save vilanele/1d0396e3d602be9ab84e31ec1354697f to your computer and use it in GitHub Desktop.
Grobner bases over polyhedral algebras
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing | |
from sage.structure.unique_representation import UniqueRepresentation | |
from sage.structure.parent import Parent | |
from sage.structure.category_object import normalize_names | |
from sage.categories.algebras import Algebras | |
from sage.modules.free_module_element import vector | |
from sage.geometry.polyhedral_complex import Polyhedron | |
from sage.geometry.fan import Fan | |
from sage.geometry.cone import Cone | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.rings.infinity import Infinity | |
from sage.plot.plot import plot | |
from sage.structure.element import CommutativeAlgebraElement | |
from sage.rings.polynomial.polydict import PolyDict | |
from sage.modules.free_module_element import vector | |
from sage.geometry.polyhedral_complex import Polyhedron | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.rings.infinity import Infinity | |
from sage.monoids.monoid import Monoid_class | |
from sage.structure.unique_representation import UniqueRepresentation | |
from sage.rings.infinity import Infinity | |
from sage.structure.element import MonoidElement | |
from sage.rings.polynomial.polydict import ETuple | |
class PositiveExponentsAlgebraElement(CommutativeAlgebraElement): | |
def __init__(self, parent, x=None, prec=None): | |
CommutativeAlgebraElement.__init__(self, parent) | |
if isinstance(x, PositiveExponentsAlgebraElement): | |
self._poly = x._poly | |
if prec is None: | |
self._prec = x._prec | |
else: | |
self._prec = prec | |
elif isinstance(x, PositiveExponentsTerm): | |
self._poly = parent._polynomial_ring( | |
PolyDict({x.exponent(): parent._field(x.coefficient())}) | |
) | |
self._prec = Infinity | |
else: | |
try: | |
self._poly = parent._polynomial_ring(x) | |
if prec is None: | |
self._prec = Infinity | |
else: | |
self._prec = prec | |
except TypeError: | |
raise | |
def terms(self): | |
r""" | |
Return the terms of ``self`` in a list, sorted by decreasing order. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.terms() | |
[(1 + O(2^20))*y, (2 + O(2^21))*x, (1 + O(2^20))*x*y] | |
""" | |
terms = [ | |
PositiveExponentsTerm(self.parent()._monoid_of_terms, coeff=c, exponent=e) | |
for e, c in self._poly.dict().items() | |
] | |
return sorted(terms, reverse=True) | |
def leading_term(self, i=None): | |
r""" | |
Return the leading term of this series if ``i`` is None, otherwise the | |
leading term for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_term() | |
(1 + O(2^20))*y | |
sage: f.leading_term(1) | |
(2 + O(2^21))*x | |
""" | |
if i is None: | |
return self.terms()[0] | |
lt = self.initial(i)._poly.leading_term() | |
return PositiveExponentsTerm( | |
self.parent()._monoid_of_terms, lt.coefficients()[0], lt.exponents()[0] | |
) | |
def leading_monomial(self, i=None): | |
r""" | |
Return the leading monomial of this series if ``i`` is None, otherwise the | |
leading monomial for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_monomial() | |
(1 + O(2^20))*y | |
sage: f.leading_monomial(1) | |
(1 + O(2^20))*x | |
""" | |
return self.leading_term(i).monomial() | |
def leading_coefficient(self, i=None): | |
r""" | |
Return the leading coefficient of this series if ``i`` is None, otherwise the | |
leading coefficient for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_coefficient() | |
1 + O(2^20) | |
sage: f.leading_coefficient(1) | |
2 + O(2^21) | |
""" | |
return self.leading_term(i).coefficient() | |
def leadings(self, i=None): | |
r""" | |
Return a list containing the leading coefficient, monomial and term | |
of this series if ``i`` is None, or th same for the ``i``-th vertex otherwise. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leadings() | |
(1 + O(2^20), (1 + O(2^20))*y, (1 + O(2^20))*y) | |
""" | |
lt = self.leading_term(i) | |
return (lt.coefficient(), lt.monomial(), lt) | |
def initial(self, i=None): | |
r""" | |
Return the initial part of this series if ``i`` is None, otherwise | |
the initial part for the ``i``-the vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.initial() | |
(1 + O(2^20))*y | |
sage: f.initial(1) | |
(1 + O(2^20))*y + (2 + O(2^21))*x | |
""" | |
terms = self.terms() | |
if i is None: | |
v = self.valuation() | |
else: | |
v = min([t.valuation(i) for t in terms]) | |
return sum( | |
[self.__class__(self.parent(), t) for t in terms if t.valuation(i) == v] | |
) | |
def valuation(self, i=None): | |
r""" | |
Return the valuation of this series if ``i`` is None | |
(which is the minimum over the valuations at each vertex), | |
otherwise the valuation for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.valuation() | |
1 | |
""" | |
if self.is_zero(): | |
return Infinity | |
return self.leading_term(i).valuation(i) | |
def _normalize(self): | |
r""" | |
Normalize this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.add_bigoh(2) # Indirect doctest | |
(1 + O(2))*y + OO(2) | |
""" | |
if self._prec == Infinity: | |
return | |
terms = [] | |
for t in self.terms(): | |
exponent = t.exponent() | |
coeff = t.coefficient() | |
v = max( | |
[ | |
ETuple(tuple(vertex)).dotprod(exponent) | |
for vertex in self.parent().vertices() | |
] | |
) | |
if coeff.precision_absolute() > self._prec + v: | |
coeff = coeff.add_bigoh(self._prec + v) | |
if coeff.valuation() < self._prec + v: | |
t._coeff = coeff | |
terms.append(t) | |
self._poly = sum([self.__class__(self.parent(), t)._poly for t in terms]) | |
def add_bigoh(self, prec): | |
r""" | |
Return this series truncated to precision ``prec``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.add_bigoh(2) | |
(1 + O(2))*y + OO(2) | |
""" | |
return self.parent()(self, prec=prec) | |
def is_zero(self): | |
r""" | |
Test if series is zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.is_zero() | |
False | |
sage: (f-f).is_zero() | |
True | |
""" | |
# self._normalize() | |
return self._poly == 0 | |
def __eq__(self, other): | |
r""" | |
Test equality of this series and ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = 3*x*y | |
sage: f == g | |
False | |
sage: f == f | |
True | |
""" | |
diff = self - other | |
return diff.is_zero() | |
def _add_(self, other): | |
r""" | |
Return the addition of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = 3*x*y | |
sage: f + g | |
(1 + O(2^20))*y + (2 + O(2^21))*x + (2^2 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly + other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _sub_(self, other): | |
r""" | |
Return the substraction of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x + y | |
sage: f - g | |
(1 + O(2^20))*x + (1 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly - other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this series and ``other`. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x + y | |
sage: f*g | |
(1 + O(2^20))*y^2 + (1 + 2 + O(2^20))*x*y + (2 + O(2^21))*x^2 + (1 + O(2^20))*x*y^2 + (1 + O(2^20))*x^2*y | |
""" | |
a = self.valuation() + other._prec | |
b = other.valuation() + self._prec | |
prec = min(a, b) | |
ans = self.__class__(self.parent(), self._poly * other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _neg_(self): | |
r""" | |
Return the negation of this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = -x | |
sage: -f | |
(1 + O(2^20))*x | |
""" | |
ans = self.__class__(self.parent(), -self._poly, prec=self._prec) | |
ans._normalize() | |
return ans | |
def _repr_(self): | |
r""" | |
Return a string representation of this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: x | |
(1 + O(2^20))*x | |
""" | |
self._normalize() | |
terms = self.terms() | |
r = "" | |
for t in terms: | |
if t.valuation() < self._prec: | |
s = repr(t) | |
if r == "": | |
r += s | |
elif s[0] == "-": | |
r += " - " + s[1:] | |
else: | |
r += " + " + s | |
if not self._prec == Infinity: | |
if r: | |
r += " + " | |
r += f"OO({self._prec})" | |
return r | |
def _quo_rem(self, divisors, quotients=False, verbose=False): | |
r""" | |
Perform the reduction of ``self`` by quotients. For this method to terminate, | |
it is necessary that ``self`` have finite precision. If not, we use | |
the precision cap of the parent algebra. | |
The flag ``quotients`` indicate wether to return the quotients with the remainder. | |
The flag ``verbose`` trigger some basic traceback. | |
""" | |
if self.is_zero(): | |
raise ValueError("Quo_rem for zero") | |
divisors = [d for d in divisors if not d.is_zero()] | |
zero = self.parent().zero() | |
remainder = zero | |
Q = [zero for _ in range(len(divisors))] | |
f = self.parent()(self) | |
if f._prec is Infinity: | |
f.add_bigoh(f.parent()._prec) | |
# print(f) | |
if verbose: | |
print("Starting main loop ...") | |
while not f.is_zero(): | |
if verbose: | |
print("NNEWWWWWWWWWWW LOOOOOOOOP") | |
print(f) | |
print(f._poly) | |
print(f.is_zero()) | |
ltf = f.leading_term() | |
v, i = ltf.valuation(vertex_index=True) | |
if verbose: | |
print(f"leading: {ltf}, valuation: {v}, index: {i}") | |
found_reducer = False | |
if verbose: | |
print("Looking for reducer ...") | |
for k in range(len(divisors)): | |
d = divisors[k] | |
ltig = d.leading_term(i) | |
if verbose: | |
print(f"Tryind divisor {d} with lt at {i} : {ltig}") | |
print("Testing terms divisibility ...") | |
if ltf._is_divisible_by(ltig): | |
t = ltf._divides(ltig) | |
if verbose: | |
print(f"Divisibility is ok, quotient is: {t}") | |
td = t * d | |
if verbose: | |
print(f"Tentative reducer: {td}") | |
if td.leading_term().same(ltf): | |
if verbose: | |
print("Reducter found !!") | |
print(f"Valuation of f before : {f.valuation()} ") | |
print(f"Poly of f before: {f._poly}") | |
print(f"TD = {td}") | |
found_reducer = True | |
f = f - td | |
# print(f._prec) | |
if verbose: | |
print(f"Valuation of f after : {f.valuation()} ") | |
print(f"Poly of f after {f._poly}") | |
if quotients: | |
Q[k] += self.__class__(self.parent(), t._to_poly()) | |
break | |
if not found_reducer: | |
if verbose: | |
print("No reducer found, moving to remainder ...") | |
print(f"Valuation of f before : {f.valuation()} ") | |
remainder += self.__class__(self.parent(), ltf._to_poly()) | |
f = f - self.__class__(self.parent(), ltf._to_poly()) | |
if verbose: | |
print(f"Valuation of f after : {f.valuation()} ") | |
print(f"Current state of remainder : {remainder}") | |
rprec = min(f._prec, *[q.valuation() + d._prec for q, d in zip(Q, divisors)]) | |
remainder = remainder.add_bigoh(rprec) | |
if quotients: | |
return Q, remainder | |
else: | |
return remainder | |
def leading_module_polyhedron(self, i=None, backend="normaliz"): | |
r""" | |
Return the polyhedron whose intger points are exactly the exponents of all | |
leadings terms of multiple of this series that lie in the restricted | |
``i``-th cone. | |
Is ``i`` is None, return a list with all polyhedron for all vertices. | |
The default backend for the polyhedron class is normaliz. It is needed | |
for the method least_common_multiples to retrieve integral generators. | |
If you only wan't to construct the polyhedron, any backend is ok. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_module_polyhedron() | |
[A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays, A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays] | |
sage: f.leading_module_polyhedron(0) | |
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays | |
""" | |
if i is None: | |
return [ | |
self.leading_module_polyhedron(i, backend) | |
for i in range(self.parent()._nvertices) | |
] | |
vertices = self.parent()._vertices | |
ieqs = [] | |
shift = vector(self.leading_monomial(i).exponent()) | |
for j in [k for k in range(len(vertices)) if k != i]: | |
v = vertices[j] | |
a = tuple(vector(vertices[i]) - vector(v)) | |
c = self.valuation(i) - self.valuation(j) | |
if j < i: | |
c += 1 | |
ieqs.append((-c,) + a) | |
P1 = Polyhedron(ieqs=ieqs).intersection(self.parent()._quadrant) | |
return Polyhedron( | |
rays=self.parent().polyhedron_at_vertex(i).rays(), | |
vertices=[list(vector(v) + shift) for v in P1.vertices()], | |
backend=backend, | |
) | |
def least_common_multiples(self, other, i): | |
r""" | |
Return the finite sets of monomials which are the lcms of this series and ``other`` | |
for the ``i``-th cone. | |
This method require the backend normaliz. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x - y | |
sage: f.least_common_multiples(g,0) | |
[(1 + O(2^20))*y] | |
""" | |
return [ | |
self.parent()._monoid_of_terms(1, exponent=tuple(e)) | |
for e in self.leading_module_polyhedron(i) | |
.intersection(other.leading_module_polyhedron(i)) | |
.integral_points_generators()[0] | |
] | |
def critical_pair(self, other, i, lcm): | |
r""" | |
Return the S-pair of this series and ``other`` for the ``i``-th | |
cone given a leading common multiple ``lcm``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x - y | |
sage: lcm = f.least_common_multiples(g,1)[0] | |
sage: f.critical_pair(g, 1, lcm) | |
(1 + 2 + O(2^20))*x^2*y + (1 + O(2^20))*x^3*y | |
""" | |
lcf, lmf, _ = self.leadings(i) | |
lcg, lmg, _ = other.leadings(i) | |
return lcg * lcm._divides(lmf) * self - lcf * lcm._divides(lmg) * other | |
def all_critical_pairs(self, other, i=None): | |
r""" | |
Return all S-pairs of this series and ``other`` for the ``i``-th cone, | |
or all S-pairs for all cones if ``i`` is None. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x + y | |
sage: f.all_critical_pairs(g,0) | |
[(1 + O(2^20))*x + (1 + O(2^20))*x*y] | |
""" | |
if i is None: | |
return [ | |
item | |
for j in range(self.parent()._nvertices) | |
for item in self.all_critical_pairs(other, j) | |
] | |
lcms = self.least_common_multiples(other, i) | |
return [self.critical_pair(other, i, lcm) for lcm in lcms] | |
class PositiveExponentsAlgebra(Parent, UniqueRepresentation): | |
r""" | |
Parent class for series with finite precision in a polyhedral algebra with positivce exponents. | |
""" | |
Element = PositiveExponentsAlgebraElement | |
def __init__(self, field, polyhedron, names, order="degrevlex", prec=10): | |
self.element_class = PositiveExponentsAlgebraElement | |
self._field = field | |
self._prec = prec | |
self._polyhedron = polyhedron | |
self._vertices = polyhedron.vertices() | |
self._nvertices = len(self._vertices) | |
self._names = normalize_names(-1, names) | |
self._polynomial_ring = PolynomialRing(field, names=names, order=order) | |
self._monoid_of_terms = PositiveExponentsTermMonoid(self) | |
self._gens = [ | |
self.element_class(self, g, prec=Infinity) | |
for g in self._polynomial_ring.gens() | |
] | |
self._ngens = len(self._gens) | |
from sage.geometry.cone_catalog import nonnegative_orthant | |
self._quadrant = nonnegative_orthant(self._ngens).polyhedron() | |
Parent.__init__(self, names=names, category=Algebras(self._field).Commutative()) | |
def term_order(self): | |
r""" | |
Return the term order used to break ties. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.term_order() | |
Degree reverse lexicographic term order | |
""" | |
return self._polynomial_ring.term_order() | |
def variable_names(self): | |
r""" | |
Return the variables names of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, there are no inter-algebras coercions, we only coerce from | |
the coefficient field or the corresponding term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: 2*x #indirect doctest | |
(2 + O(2^21))*x | |
sage: x.leading_term()*(x+y) | |
(1 + O(2^20))*x^2 + (1 + O(2^20))*x*y | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
elif isinstance(R, PositiveExponentsTermMonoid): | |
return True | |
else: | |
return False | |
def field(self): | |
r""" | |
Return the coefficient field of this algebra (currently restricted to Qp). | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this algebra. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.prime() | |
2 | |
""" | |
return self._field.prime() | |
def gen(self, n=0): | |
r""" | |
Return the ``n``-th generator of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.gen(1) | |
(1 + O(2^20))*y | |
""" | |
if n < 0 or n >= self._ngens: | |
raise IndexError("Generator index out of range") | |
return self._gens[n] | |
def gens(self): | |
r""" | |
Return the list of generators of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.gens() | |
[(1 + O(2^20))*x, (1 + O(2^20))*y] | |
""" | |
return self._gens | |
def ngens(self): | |
r""" | |
Return the number of generators of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.ngens() | |
2 | |
""" | |
return len(self._gens) | |
def zero(self): | |
r""" | |
Return the element 0 of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.zero() | |
""" | |
return self(0) | |
def polyhedron(self): | |
r""" | |
Return the defining polyhedron of this algebra. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.polyhedron() | |
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays | |
""" | |
return self._polyhedron | |
def vertices(self): | |
r""" | |
Return the list of vertices of the defining polyhedron of this algebra. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.vertices() | |
(A vertex at (-2, -1), A vertex at (-1, -2)) | |
""" | |
return self._vertices | |
def monoid_of_terms(self): | |
r""" | |
Return the monoid of terms for this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.monoid_of_terms() | |
monoid of terms | |
""" | |
return self._monoid_of_terms | |
def vertex(self, i=0, etuple=False): | |
r""" | |
Return the ``i``-th vertex of the defining polyhedron (indexing starts at zero). | |
The flag ``etuple`` indicates whether the result should be returned as an ``ETuple``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.vertex(0) | |
A vertex at (-2, -1) | |
sage: A.vertex(1, etuple=True) | |
(-1, -2) | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
if etuple: | |
return ETuple(tuple(self.vertex(i))) | |
return self._vertices[i] | |
def vertex_indices(self): | |
r""" | |
Return the list of verex indices. Indexing starts at zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.vertex_indices() | |
[0, 1] | |
""" | |
return [i for i in range(self._nvertices)] | |
def cone_at_vertex(self, i=0): | |
r""" | |
Return the cone for the ``i``-th vertex of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: C = A.cone_at_vertex(0); C | |
2-d cone in 2-d lattice N | |
sage: C.rays() | |
N(1, 1), | |
N(0, 1) | |
in 2-d lattice N | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
return Cone(self.polyhedron_at_vertex(i)) | |
def polyhedron_at_vertex(self, i=0): | |
r""" | |
Return the the cone for the ``i``-th vertex as a polyhedron. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: C = A.polyhedron_at_vertex(0); C | |
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
ieqs = [] | |
for v in self._vertices[:i] + self._vertices[i + 1 :]: | |
a = tuple(vector(self._vertices[i]) - vector(v)) | |
ieqs.append((0,) + a) | |
return Polyhedron(ieqs=ieqs).intersection(self._quadrant) | |
def plot_leading_monomials(self, G): | |
r""" | |
Experimental. Plot in the same graphics all polyhedrons containing | |
the leading monomials of the series in the list ``G``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.plot_leading_monomials([2*x + y, x**2 - 3*y**3]) | |
Graphics object consisting of 17 graphics primitives | |
""" | |
plots = [] | |
for g in G: | |
plots += [plot(p) for p in g.leading_module_polyhedron()] | |
return sum(plots) | |
def fan(self): | |
r""" | |
Return the fan whose maximal cones are the cones at each vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: A.fan() | |
Rational polyhedral fan in 2-d lattice N | |
""" | |
cones = [] | |
for i in range(len(self._vertices)): | |
cones.append(Cone(self.cone_at_vertex(i))) | |
return Fan(cones=cones) | |
def ideal(self, G): | |
r""" | |
Return the ideal generated by the list of series ``G``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: I = A.ideal([x,y]); | |
""" | |
return PositiveExponentsAlgebraIdeal(G) | |
class PositiveExponentsTerm(MonoidElement): | |
def __init__(self, parent, coeff, exponent=None): | |
MonoidElement.__init__(self, parent) | |
field = parent._field | |
if isinstance(coeff, PositiveExponentsTerm): | |
if coeff.parent().variable_names() != self.parent().variable_names(): | |
raise ValueError("the variable names do not match") | |
self._coeff = field(coeff._coeff) | |
self._exponent = coeff._exponent | |
else: | |
self._coeff = field(coeff) | |
if self._coeff.is_zero(): | |
raise TypeError("a term cannot be zero") | |
self._exponent = ETuple([0] * parent.ngens()) | |
if exponent is not None: | |
if not isinstance(exponent, ETuple): | |
exponent = ETuple(exponent) | |
self._exponent = self._exponent.eadd(exponent) | |
if len(self._exponent) != parent.ngens(): | |
raise ValueError( | |
"the length of the exponent does not match the number of variables" | |
) | |
for i in self._exponent.nonzero_positions(): | |
if self._exponent[i] < 0: | |
raise ValueError("only nonnegative exponents are allowed") | |
def coefficient(self): | |
r""" | |
Return the coefficient of this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_term().coefficient() | |
1 + O(2^20) | |
""" | |
return self._coeff | |
def exponent(self): | |
r""" | |
Return the exponent of this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_term().exponent() | |
(0, 1) | |
""" | |
return self._exponent | |
def valuation(self, i=None, vertex_index=False): | |
r""" | |
Return the valuation of this term if ``i`` is None | |
(which is the minimum over the valuations at each vertex), | |
otherwise the valuation for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_term().valuation() | |
1 | |
""" | |
if self._coeff == 0: | |
return Infinity | |
if i is None: | |
m = min([(self.valuation(j), j) for j in self.parent().vertex_indices()]) | |
if vertex_index: | |
return m | |
else: | |
return m[0] | |
return self._coeff.valuation() - self._exponent.dotprod( | |
self.parent().vertex(i, etuple=True) | |
) | |
def monomial(self): | |
r""" | |
Return this term divided by its coefficient. x. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f.leading_term().monomial() | |
(1 + O(2^20))*y | |
""" | |
coeff = self.parent()._field(1) | |
exponent = self._exponent | |
return self.__class__(self.parent(), coeff, exponent) | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this term by ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: g = x + y | |
sage: f.leading_term()*g.leading_term() | |
(1 + O(2^20))*y^2 | |
""" | |
coeff = self._coeff * other._coeff | |
exponent = self._exponent.eadd(other._exponent) | |
return self.__class__(self.parent(), coeff, exponent) | |
def _to_poly(self): | |
r""" | |
Return this term as a polynomial. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: type(f.leading_term()._to_poly()) | |
<class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'> | |
""" | |
R = self.parent()._parent_algebra._polynomial_ring | |
return self._coeff * R.monomial(self._exponent) | |
def _is_divisible_by(self, t): | |
r""" | |
Test if this term is divisible by ``t``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a._is_divisible_by(a) | |
True | |
""" | |
return t.exponent().divides(self.exponent()) | |
def _divides(self, t): | |
r""" | |
Return this term divided by ``t``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a._divides(a) | |
(1 + O(2^20)) | |
""" | |
if not self._is_divisible_by(t): | |
raise ValueError("Trying to divides two terms that can't be divided") | |
coeff = self._coeff / t._coeff | |
exponent = self._exponent.esub(t._exponent) | |
return self.__class__(self.parent(), coeff=coeff, exponent=exponent) | |
def _cmp_(self, other, i=None): | |
r""" | |
Compare this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a._cmp_(a) | |
0 | |
""" | |
ov, oi = other.valuation(vertex_index=True) | |
sv, si = self.valuation(vertex_index=True) | |
c = ov - sv | |
if c == 0: | |
c = oi - si | |
if c == 0: | |
skey = self.parent()._sortkey | |
ks = skey(self._exponent) | |
ko = skey(other._exponent) | |
c = (ks > ko) - (ks < ko) | |
return c | |
def same(self, t): | |
r""" | |
Test wether this termù is the same as ``t``, meaning | |
it has the same coefficient and exponent. | |
This is not the same as equality. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a.same(a) | |
True | |
""" | |
return self._coeff == t._coeff and self._exponent == t._exponent | |
def __eq__(self, other): | |
r""" | |
Test quality of this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a == a | |
True | |
sage: a == x.leading_term() | |
False | |
""" | |
return self._cmp_(other) == 0 | |
def __ne__(self, other): | |
r""" | |
Test inquality of this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: a != a | |
False | |
sage: a != x.leading_term() | |
True | |
""" | |
return not self == other | |
def __lt__(self, other): | |
r""" | |
Test if this term is less than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a < b | |
False | |
""" | |
return self._cmp_(other) < 0 | |
def __gt__(self, other): | |
r""" | |
Test if this term is greater than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a > b | |
True | |
""" | |
return self._cmp_(other) > 0 | |
def __le__(self, other): | |
r""" | |
Test if this term is less than or equal than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a <= b | |
False | |
""" | |
return self._cmp_(other) <= 0 | |
def __ge__(self, other): | |
r""" | |
Test if this term is greater than or equal than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a >= b | |
True | |
""" | |
return self._cmp_(other) >= 0 | |
def _repr_(self): | |
r""" | |
Return a string representing this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f | |
(1 + O(2^20))*y + (2 + O(2^21))*x + (1 + O(2^20))*x*y | |
""" | |
parent = self.parent() | |
if self._coeff._is_atomic() or (-self._coeff)._is_atomic(): | |
s = repr(self._coeff) | |
if s == "1": | |
s = "" | |
else: | |
s = "(%s)" % self._coeff | |
for i in range(parent._ngens): | |
if self._exponent[i] == 1: | |
s += "*%s" % parent._names[i] | |
elif self._exponent[i] > 1: | |
s += "*%s^%s" % (parent._names[i], self._exponent[i]) | |
if s[0] == "*": | |
return s[1:] | |
else: | |
return s | |
class PositiveExponentsTermMonoid(Monoid_class, UniqueRepresentation): | |
Element = PositiveExponentsTerm | |
def __init__(self, parent_algebra): | |
self.element_class = PositiveExponentsTerm | |
names = parent_algebra.variable_names() | |
Monoid_class.__init__(self, names=names) | |
self._field = parent_algebra._field | |
self._names = names | |
self._ngens = len(names) | |
self._vertices = parent_algebra._vertices | |
self._nvertices = parent_algebra._nvertices | |
self._order = parent_algebra.term_order() | |
self._sortkey = self._order.sortkey | |
self._parent_algebra = parent_algebra | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, we only coerce from coefficient ring. | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
else: | |
return False | |
def _repr_(self): | |
r""" | |
Return a string representation of this term monoid. | |
""" | |
return "monoid of terms" | |
def vertex_indices(self): | |
r""" | |
Return the list of verex indices. Indexing starts at zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.vertex_indices() | |
[0, 1] | |
""" | |
return [i for i in range(self._nvertices)] | |
def field(self): | |
r""" | |
Return the coefficient field of this term monoid. | |
This is the same as for the parent algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this term monoid. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.prime() | |
2 | |
""" | |
return self._field.prime() | |
def parent_algebra(self): | |
r""" | |
Return the parent algebra of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: PA = M.parent_algebra() | |
""" | |
return self._parent_algebra | |
def term_order(self): | |
r""" | |
Return the term order used to break ties. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.term_order() | |
Degree reverse lexicographic term order | |
""" | |
return self._order | |
def variable_names(self): | |
r""" | |
Return the variables names of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def vertices(self): | |
r""" | |
Return the list of vertices of the defining polyhedron of the parent algebra | |
of this term monoid. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.vertices() | |
(A vertex at (-2, -1), A vertex at (-1, -2)) | |
""" | |
return self._vertices | |
def vertex(self, i=0, etuple=False): | |
r""" | |
Return the ``i``-th vertex of the defining polyhedron (indexing starts at zero) | |
of the parent algebra. | |
The flag ``etuple`` indicates whether the result should be returned as an ``ETuple``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.vertex(0) | |
A vertex at (-2, -1) | |
sage: M.vertex(1, etuple=True) | |
(-1, -2) | |
""" | |
return self._parent_algebra.vertex(i, etuple=etuple) | |
def ngens(self): | |
r""" | |
Return the number of generators of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: M = A.monoid_of_terms() | |
sage: M.ngens() | |
2 | |
""" | |
return self._ngens | |
class PositiveExponentsAlgebraIdeal: | |
def __init__(self, G): | |
r""" | |
Create a new ideal from list of generators ``G``. | |
""" | |
self._G = G | |
self._parent = G[0].parent() | |
def groebner_basis(self): | |
r""" | |
Basic naive Buchberger algorithm. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 3*x*y^2 + 4*x^3 | |
sage: f = f.add_bigoh(10) | |
sage: g = 3*x^2*y^2 + 8*x^2*y | |
sage: g = g.add_bigoh(10) | |
sage: I = A.ideal([g,f]) | |
sage: I.groebner_basis() | |
[(1 + 2 + O(2^4))*x^2*y^2 + (2^3 + O(2^6))*x^2*y + OO(10), | |
(1 + 2 + O(2^6))*x*y^2 + (2^2 + O(2^7))*x^3 + OO(10), | |
(2^2 + 2^4 + 2^5 + O(2^6))*x^4 + (2^3 + 2^4 + O(2^6))*x^2*y + OO(10)] | |
""" | |
G = self._G | |
G = [g if g._prec != Infinity else g.add_bigoh(g.parent()._prec) for g in G] | |
P = [[G[i], G[j]] for i in range(len(G)) for j in range(len(G)) if i < j] | |
while len(P) > 0: | |
[f, g] = P.pop() | |
SPairs = f.all_critical_pairs(g) | |
for S in SPairs: | |
if not S.is_zero(): | |
r = S._quo_rem(G) | |
if not r.is_zero(): | |
P += [[g, r] for g in G] | |
G = G + [r] | |
return G |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing | |
from sage.structure.unique_representation import UniqueRepresentation | |
from sage.structure.parent import Parent | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.structure.category_object import normalize_names | |
from sage.categories.algebras import Algebras | |
from sage.rings.infinity import Infinity | |
from sage.structure.element import CommutativeAlgebraElement | |
from sage.rings.polynomial.polydict import PolyDict | |
from sage.rings.infinity import Infinity | |
from sage.rings.infinity import Infinity | |
from sage.structure.element import MonoidElement | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.monoids.monoid import Monoid_class | |
from sage.rings.polytopal.PolyCircleTerm import PolyCircleTerm | |
from sage.structure.unique_representation import UniqueRepresentation | |
from sage.rings.integer_ring import ZZ | |
from sage.modules.free_module_element import vector | |
from sage.rings.polynomial.term_order import TermOrder | |
from sage.matrix.constructor import matrix | |
from sage.structure.sage_object import SageObject | |
class GeneralizedOrder(SageObject): | |
def __init__(self, n, group_order="lex", score_function="min"): | |
r""" | |
Create a generalized monomial order in ``n`` varaibles with optional group order and score function. | |
INPUT: | |
- ``n`` -- the number of variables | |
- ``group_order`` (default: ``lex``) -- the name of a group order on `\ZZ^n`, choices are: "lex" | |
- ``score_function`` (default: ``min``) -- the name of a score function, choices are: "min", "degmin" | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: GeneralizedOrder(2) | |
Generalized monomial order in 2 variables using (lex, min) | |
sage: GeneralizedOrder(8, group_order="lex") | |
Generalized monomial order in 8 variables using (lex, min) | |
sage: GeneralizedOrder(3, score_function="min") | |
Generalized monomial order in 3 variables using (lex, min) | |
sage: GeneralizedOrder(3, group_order="lex", score_function="degmin") | |
Generalized monomial order in 3 variables using (lex, degmin) | |
""" | |
self._n = n | |
self._n_cones = self._n + 1 | |
# Build cones | |
self._cones = [matrix.identity(ZZ, n)] | |
for i in range(0, n): | |
mat = matrix.identity(ZZ, n) | |
mat.set_column(i, vector(ZZ, [-1] * n)) | |
self._cones.append(mat) | |
# Set group order. Add more here. | |
if group_order in ["lex"]: | |
self._group_order = TermOrder(name=group_order) | |
else: | |
raise ValueError("Available group order are: 'lex'") | |
# Set score function. Add more here. | |
if score_function == "min": | |
self._score_function = min_score_function | |
elif score_function == "degmin": | |
self._score_function = degmin_score_function | |
else: | |
raise ValueError("Available score function are: 'min', 'degmin'") | |
# Store names | |
self._group_order_name = group_order | |
self._score_function_name = score_function | |
def _repr_(self): | |
r""" | |
TESTS:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: GeneralizedOrder(2)._repr_() | |
'Generalized monomial order in 2 variables using (lex, min)' | |
""" | |
group = self._group_order_name | |
function = self._score_function_name | |
n = str(self._n) | |
return "Generalized monomial order in %s variables using (%s, %s)" % ( | |
n, | |
group, | |
function, | |
) | |
def __hash__(self): | |
r""" | |
Return the hash of self. It depends on the number of variables, the group_order and the score function. | |
""" | |
return hash(self._group_order_name + self._score_function_name + str(self._n)) | |
def n_cones(self): | |
r""" | |
Return the number of cones (which is the number of variables plus one). | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.n_cones() | |
3 | |
""" | |
return self._n_cones | |
def cones(self): | |
r""" | |
Return the list of matrices containing the generators of the cones. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.cones() | |
[ | |
[1 0] [-1 0] [ 1 -1] | |
[0 1], [-1 1], [ 0 -1] | |
] | |
""" | |
return self._cones | |
def cone(self, i): | |
r""" | |
Return the matrix whose columns are the generators of the ``i``-th cone. | |
INPUT: | |
- `i` -- an integer, a cone index | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.cone(1) | |
[-1 0] | |
[-1 1] | |
""" | |
if i < 0 or i > self._n: | |
raise IndexError("cone index out of range") | |
return self._cones[i] | |
def group_order(self): | |
r""" | |
Return the underlying group order. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: G = GeneralizedOrder(2) | |
sage: G.group_order() | |
Lexicographic term order | |
""" | |
return self._group_order | |
def group_order_name(self): | |
r""" | |
Return the name of the underlying group order. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2,group_order="lex") | |
sage: order.group_order_name() | |
'lex' | |
""" | |
return self._group_order_name | |
def score_function_name(self): | |
r""" | |
Return the name of the underlying score function. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2,score_function="degmin") | |
sage: order.score_function_name() | |
'degmin' | |
""" | |
return self._score_function_name | |
def score(self, t): | |
r""" | |
Compute the score of a tuple ``t``. | |
INPUT: | |
- `t` -- a tuple of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.score((-2,3)) | |
2 | |
""" | |
return self._score_function(t) | |
def compare(self, a, b): | |
r""" | |
Return 1, 0 or -1 whether tuple ``a`` is greater than, equal or less than to tuple ``b`` respectively. | |
INPUT: | |
- `a` and `b` -- two tuples of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(3) | |
sage: order.compare((1,2,-2), (3,-4,5)) | |
-1 | |
sage: order.compare((3,-4,5), (1,2,-2)) | |
1 | |
sage: order.compare((3,-4,5), (3,-4,5)) | |
0 | |
""" | |
if a == b: | |
return 0 | |
diff = self._score_function(a) - self._score_function(b) | |
if diff != 0: | |
return 1 if diff > 0 else -1 | |
else: | |
return 1 if self._group_order.greater_tuple(a, b) == a else -1 | |
def greatest_tuple(self, *L): | |
r""" | |
Return the greatest tuple in ``L``. | |
INPUT: | |
- *L -- integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(3) | |
sage: order.greatest_tuple((0,0,1),(2,3,-2)) | |
(2, 3, -2) | |
sage: L = [(1,2,-1),(3,-3,0),(4,-5,-6)] | |
sage: order.greatest_tuple(*L) | |
(4, -5, -6) | |
""" | |
n = len(L) | |
if n == 0: | |
raise ValueError("empty list of tuples") | |
if n == 1: | |
return L[0] | |
else: | |
a = L[0] | |
b = self.greatest_tuple(*L[1:]) | |
return a if self.compare(a, b) == 1 else b | |
def translate_to_cone(self, i, L): | |
r""" | |
Return a tuple ``t`` such that `t + L` is contained in the ``i``-th cone. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L`` -- a list of integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.translate_to_cone(0, [(1,2),(-2,-3),(1,-4)]) | |
(2, 4) | |
""" | |
# print(L) | |
cone_matrix = self._cones[i] | |
T = matrix(ZZ, [cone_matrix * vector(v) for v in L]) | |
return tuple(cone_matrix * vector([-min(0, *c) for c in T.columns()])) | |
def greatest_tuple_for_cone(self, i, *L): | |
r""" | |
Return the greatest tuple of the list of tuple `L` with respect to the `i`-th cone. | |
This is the unique tuple `t` in `L` such that each time the greatest tuple of `s + L` | |
for a tuple `s` is contained in the `i`-th cone, it is equal to `s + t`. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L`` -- a list of integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: L = [(1,2), (-2,-2), (-4,5), (5,-6)] | |
sage: t = order.greatest_tuple_for_cone(1, *L);t | |
(-4, 5) | |
We can check the result:: | |
sage: s = order.translate_to_cone(1, L) | |
sage: sL = [tuple(vector(s) + vector(l)) for l in L] | |
sage: tuple(vector(s) + vector(t)) == order.greatest_tuple(*sL) | |
True | |
""" | |
t = vector(self.translate_to_cone(i, L)) | |
L = [vector(l) for l in L] | |
return tuple(vector(self.greatest_tuple(*[tuple(t + l) for l in L])) - t) | |
def is_in_cone(self, i, t): | |
r""" | |
Test whether the tuple ``t`` is contained in the ``i``-th cone or not. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``t`` -- a tuple of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: order.is_in_cone(0, (1,2)) | |
True | |
sage: order.is_in_cone(0,(-2,3)) | |
False | |
""" | |
return all(c >= 0 for c in self.cone(i) * vector(t)) | |
def generator(self, i, L): | |
r""" | |
Return the generator of the module over the ``i``-th cone for ``L``. | |
This is the monoïd of elements `t \in \ZZ^n` such that the greatest | |
tuple of `t + L` is contained in the ``i``-th cone. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L`` -- a list of iinteger tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(3) | |
sage: L = [(1,2,-2), (3,4,-5), (-6,2,-7), (3,-6,1)] | |
sage: order.generator(0,L) | |
(6, 6, 7) | |
sage: order.generator(2,L) | |
(5, 5, 6) | |
""" | |
cone_matrix = self._cones[i] | |
t = vector(self.translate_to_cone(i, L)) | |
L = [vector(l) for l in L] | |
for c in cone_matrix.columns(): | |
while self.is_in_cone(i, self.greatest_tuple(*[tuple(t + l) for l in L])): | |
t = t - c | |
t = t + c | |
return tuple(t) | |
def generator_for_pair(self, i, L1, L2): | |
r""" | |
Return the generator of the module over the ``i``-th cone for ``L1`` and ``L2``. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L1`` -- a list of integer tuples | |
- ``L2`` -- a list of integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: order = GeneralizedOrder(2) | |
sage: L1 = [(2,3),(-4,2),(-1,-2)] | |
sage: L2 = [(1,-6),(5,-2),(3,4)] | |
sage: order.generator_for_pair(1,L1,L2) | |
(1, 5) | |
""" | |
cone_matrix = self._cones[i] | |
lm1 = vector(self.greatest_tuple_for_cone(i, *L1)) | |
lm2 = vector(self.greatest_tuple_for_cone(i, *L2)) | |
g1 = vector(self.generator(i, L1)) | |
g2 = vector(self.generator(i, L2)) | |
m = vector([max(a, b) for a, b in zip(lm1 + g1, lm2 + g2)]) | |
return tuple(cone_matrix * m) | |
# Score functions. Add more here and update the __init__ method. | |
def min_score_function(t): | |
return -min(0, *t) | |
def degmin_score_function(t): | |
return sum(t) - (len(t) + 1) * min(0, *t) | |
class PolyCircleAlgebraElement(CommutativeAlgebraElement): | |
def __init__(self, parent, x=None, prec=None): | |
CommutativeAlgebraElement.__init__(self, parent) | |
if isinstance(x, PolyCircleAlgebraElement): | |
self._poly = x._poly | |
if prec is None: | |
self._prec = x._prec | |
else: | |
self._prec = prec | |
elif isinstance(x, PolyCircleTerm): | |
self._poly = parent._polynomial_ring( | |
PolyDict({x.exponent(): parent._field(x.coefficient())}) | |
) | |
self._prec = Infinity | |
else: | |
try: | |
self._poly = parent._polynomial_ring(x) | |
if prec is None: | |
self._prec = Infinity | |
else: | |
self._prec = prec | |
except TypeError: | |
raise | |
def terms(self): | |
r""" | |
Return the terms of ``self`` in a list, sorted by decreasing order. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y + x*y + y^-1 + 1*x^-3 | |
sage: f.terms() | |
[(1 + O(2^20))*x^-3, | |
(1 + O(2^20))*y^-1, | |
(1 + O(2^20))*y, | |
(1 + O(2^20))*x*y, | |
(2 + O(2^21))*x] | |
""" | |
terms = [ | |
PolyCircleTerm(self.parent()._monoid_of_terms, coeff=c, exponent=e) | |
for e, c in self._poly.dict().items() | |
] | |
return sorted(terms, reverse=True) | |
def leading_term(self, i=None): | |
r""" | |
Return the leading term of this series if ``i`` is None, otherwise the | |
leading term for the ``i``-th cone. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.leading_term() | |
(1 + O(2^20))*x | |
sage: f.leading_term(1) | |
(1 + O(2^20))*y | |
""" | |
if i is None: | |
return self.terms()[0] | |
ini = self.initial()._poly | |
le = self.parent()._order.greatest_tuple_for_cone(i, *ini.exponents()) | |
return PolyCircleTerm(self.parent()._monoid_of_terms, ini[le], le) | |
def leading_monomial(self, i=None): | |
r""" | |
Return the leading monomial of this series if ``i`` is None, otherwise the | |
leading monomial for the ``i``-th cone. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.leading_monomial() | |
(1 + O(2^20))*x | |
sage: f.leading_monomial(1) | |
(1 + O(2^20))*y | |
""" | |
return self.leading_term(i).monomial() | |
def leading_coefficient(self, i=None): | |
r""" | |
Return the leading coefficient of this series if ``i`` is None, otherwise the | |
leading coefficient for the ``i``-th cone. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.leading_coefficient() | |
1 + O(2^20) | |
sage: f.leading_coefficient(1) | |
1 + O(2^20) | |
""" | |
return self.leading_term(i).coefficient() | |
def leadings(self, i=None): | |
r""" | |
Return a list containing the leading coefficient, monomial and term | |
of this series if ``i`` is None, or th same for the ``i``-th cone otehrwise. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.leadings() | |
(1 + O(2^20), (1 + O(2^20))*x, (1 + O(2^20))*x) | |
""" | |
lt = self.leading_term(i) | |
return (lt.coefficient(), lt.monomial(), lt) | |
def initial(self): | |
r""" | |
Return the initial part of this series. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.initial() | |
(1 + O(2^20))*x + (1 + O(2^20))*y | |
""" | |
terms = self.terms() | |
v = min([t.valuation() for t in terms]) | |
return sum( | |
[self.__class__(self.parent(), t) for t in terms if t.valuation() == v] | |
) | |
def valuation(self): | |
r""" | |
Return the valuation of this series. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.valuation() | |
1 | |
""" | |
if self.is_zero(): | |
return Infinity | |
return self.leading_term().valuation() | |
def _normalize(self): | |
r""" | |
Normalize this series. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.add_bigoh(2) # Indirect doctest | |
(1 + O(2))*x + (1 + O(2))*y + OO(2) | |
""" | |
if self._prec == Infinity: | |
return | |
terms = [] | |
for t in self.terms(): | |
exponent = t.exponent() | |
coeff = t.coefficient() | |
v = self.parent().log_radii().dotprod(exponent) | |
if coeff.precision_absolute() > self._prec + v: | |
coeff = coeff.add_bigoh(self._prec + v) | |
if coeff.valuation() < self._prec + v: | |
t._coeff = coeff | |
terms.append(t) | |
self._poly = sum([self.__class__(self.parent(), t)._poly for t in terms]) | |
def add_bigoh(self, prec): | |
r""" | |
Return this series truncated to precision ``prec``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.add_bigoh(2) # Indirect doctest | |
(1 + O(2))*x + (1 + O(2))*y + OO(2) | |
""" | |
return self.parent()(self, prec=prec) | |
def is_zero(self): | |
r""" | |
Test if this series is zero. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: f.is_zero() | |
False | |
sage: (f-f).is_zero() | |
True | |
""" | |
# self._normalize() | |
return self._poly == 0 | |
def __eq__(self, other): | |
r""" | |
Test equality of this series and ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: g = 3*x*y | |
sage: f == g | |
False | |
sage: f == f | |
True | |
""" | |
diff = self - other | |
return diff.is_zero() | |
def _add_(self, other): | |
r""" | |
Return the addition of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: g = 3*x*y | |
sage: f + g | |
(1 + O(2^20))*x + (1 + O(2^20))*y + (2^2 + O(2^22))*x*y^-1 + (1 + 2 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly + other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _sub_(self, other): | |
r""" | |
Return the substraction of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: g = -3*x*y | |
sage: f - g | |
(1 + O(2^20))*x + (1 + O(2^20))*y + (2^2 + O(2^22))*x*y^-1 + (1 + 2 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly - other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this series and ``other`. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: g = 3*x*y | |
sage: f*g | |
(1 + 2 + O(2^20))*x^2*y + (1 + 2 + O(2^20))*x*y^2 + (2^2 + 2^3 + O(2^22))*x^2 | |
""" | |
a = self.valuation() + other._prec | |
b = other.valuation() + self._prec | |
prec = min(a, b) | |
ans = self.__class__(self.parent(), self._poly * other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _div_(self, other): | |
r""" | |
Return the division of this series by ``other`. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x | |
sage: g = x*y | |
sage: f/g | |
(1 + O(2^20))*y^-1 | |
""" | |
prec = self._prec - other.valuation() | |
ans = self.__class__(self.parent(), self._poly / other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _neg_(self): | |
r""" | |
Return the negation of this series. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = -x | |
sage: -f | |
(1 + O(2^20))*x | |
""" | |
ans = self.__class__(self.parent(), -self._poly, prec=self._prec) | |
ans._normalize() | |
return ans | |
def _repr_(self): | |
r""" | |
Return a string representation of this series. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: x | |
(1 + O(2^20))*x | |
""" | |
self._normalize() | |
terms = self.terms() | |
r = "" | |
for t in terms: | |
if t.valuation() < self._prec: | |
s = repr(t) | |
if r == "": | |
r += s | |
elif s[0] == "-": | |
r += " - " + s[1:] | |
else: | |
r += " + " + s | |
if not self._prec == Infinity: | |
if r: | |
r += " + " | |
r += f"OO({self._prec})" | |
return r | |
def critical_pairs(self, other, i=None): | |
r""" | |
Return all S-pairs of this series and ``other`` for the ``i``-th cone, | |
or all S-pairs for all cones if ``i`` is None. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = x + y + 4*x*y^-1 | |
sage: g = 3*x*y | |
sage: f.critical_pairs(g) | |
[(1 + 2 + O(2^20))*y^2 + (2^2 + 2^3 + O(2^22))*x, | |
(1 + 2 + O(2^20))*x*y + (2^2 + 2^3 + O(2^22))*x, | |
(1 + 2 + O(2^20))*x^-1*y + (2^2 + 2^3 + O(2^22))*y^-1] | |
""" | |
if i is None: | |
return [ | |
self.critical_pairs(other, j) | |
for j in range(self.parent()._order.n_cones()) | |
] | |
lcm = self.parent()._order.generator_for_pair( | |
i, self._poly.exponents(), other._poly.exponents() | |
) | |
lcm = PolyCircleTerm(self.parent()._monoid_of_terms, coeff=1, exponent=lcm) | |
lcf, lmf, _ = self.leadings(i) | |
lcg, lmg, _ = other.leadings(i) | |
return lcg * lcm._divides(lmf) * self - lcf * lcm._divides(lmg) * other | |
class PolyCircleAlgebra(Parent, UniqueRepresentation): | |
r""" | |
Parent class for series with finite precision in a polyhedral algebra with series converging on a poly-circle. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: x,y = A.gens() | |
""" | |
Element = PolyCircleAlgebraElement | |
def __init__( | |
self, field, log_radii, names, score_function="min", group_order="lex", prec=10 | |
): | |
self._field = field | |
self.element_class = PolyCircleAlgebraElement | |
self._prec = prec | |
self._log_radii = ETuple(log_radii) | |
self._names = normalize_names(-1, names) | |
self._polynomial_ring = LaurentPolynomialRing(field, names=names) | |
self._gens = [ | |
self.element_class(self, g, prec=Infinity) | |
for g in self._polynomial_ring.gens() | |
] | |
self._ngens = len(self._gens) | |
self._order = GeneralizedOrder( | |
self._ngens, | |
group_order=group_order, | |
score_function=score_function, | |
) | |
self._monoid_of_terms = PolyCircleTermMonoid(self) | |
Parent.__init__(self, names=names, category=Algebras(self._field).Commutative()) | |
def generalized_order(self): | |
r""" | |
Return the generalized order used to break ties. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.generalized_order() | |
Generalized monomial order in 2 variables using (lex, min) | |
""" | |
return self._order | |
def log_radii(self): | |
r""" | |
Return the log-radii of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.log_radii() | |
(-1, -1) | |
""" | |
return self._log_radii | |
def variable_names(self): | |
r""" | |
Return the variables names of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, there are no inter-algebras coercions, we only coerce from | |
the coefficient field or the corresponding term monoid. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: 2*x #indirect doctest | |
(2 + O(2^21))*x | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
elif isinstance(R, PolyCircleTermMonoid): | |
return True | |
else: | |
return False | |
def field(self): | |
r""" | |
Return the coefficient field of this algebra (currently restricted to Qp). | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this algebra. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.prime() | |
2 | |
""" | |
return self._field.prime() | |
def gen(self, n=0): | |
r""" | |
Return the ``n``-th generator of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.gen(1) | |
(1 + O(2^20))*y | |
""" | |
if n < 0 or n >= self._ngens: | |
raise IndexError("Generator index out of range") | |
return self._gens[n] | |
def gens(self): | |
r""" | |
Return the list of generators of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.gens() | |
[(1 + O(2^20))*x, (1 + O(2^20))*y] | |
""" | |
return self._gens | |
def ngens(self): | |
r""" | |
Return the number of generators of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.ngens() | |
2 | |
""" | |
return len(self._gens) | |
def zero(self): | |
r""" | |
Return the element 0 of this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.zero() | |
""" | |
return self(0) | |
def monoid_of_terms(self): | |
r""" | |
Return the monoid of terms for this algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: A.monoid_of_terms() | |
Monoid of terms for poly-circle algebra | |
""" | |
return self._monoid_of_terms | |
class PolyCircleTerm(MonoidElement): | |
def __init__(self, parent, coeff, exponent=None): | |
MonoidElement.__init__(self, parent) | |
field = parent._field | |
if isinstance(coeff, PolyCircleTerm): | |
if coeff.parent().variable_names() != self.parent().variable_names(): | |
raise ValueError("the variable names do not match") | |
self._coeff = field(coeff._coeff) | |
self._exponent = coeff._exponent | |
else: | |
self._coeff = field(coeff) | |
if self._coeff.is_zero(): | |
raise TypeError("a term cannot be zero") | |
self._exponent = ETuple([0] * parent.ngens()) | |
if exponent is not None: | |
if not isinstance(exponent, ETuple): | |
exponent = ETuple(exponent) | |
self._exponent = self._exponent.eadd(exponent) | |
if len(self._exponent) != parent.ngens(): | |
raise ValueError( | |
"the length of the exponent does not match the number of variables" | |
) | |
def coefficient(self): | |
r""" | |
Return the coefficient of this term. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().coefficient() | |
1 + O(2^20) | |
""" | |
return self._coeff | |
def exponent(self): | |
r""" | |
Return the exponent of this term. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().exponent() | |
(0, -1) | |
""" | |
return self._exponent | |
def valuation(self): | |
r""" | |
Return the valuation of this term. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().valuation() | |
-1 | |
""" | |
if self._coeff == 0: | |
return Infinity | |
return self._coeff.valuation() - self._exponent.dotprod( | |
self.parent()._log_radii | |
) | |
def monomial(self): | |
r""" | |
Return this term divided by its coefficient. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().monomial() | |
(1 + O(2^20))*y^-1 | |
""" | |
coeff = self.parent()._field(1) | |
exponent = self._exponent | |
return self.__class__(self.parent(), coeff, exponent) | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this term by ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y | |
sage: f.leading_term()*g.leading_term() | |
(1 + O(2^20))*x*y^-1 | |
""" | |
coeff = self._coeff * other._coeff | |
exponent = self._exponent.eadd(other._exponent) | |
return self.__class__(self.parent(), coeff, exponent) | |
def _to_poly(self): | |
r""" | |
Return this term as a polynomial. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: type(f.leading_term()._to_poly()) | |
<class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> | |
""" | |
R = self.parent()._parent_algebra._polynomial_ring | |
return self._coeff * R.monomial(self._exponent) | |
def _divides(self, t): | |
r""" | |
Return this term divided by ``t``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y | |
sage: a = f.leading_term() | |
sage: b = g.leading_term() | |
sage: a._divides(b) | |
(1 + O(2^20))*x^-1*y^-1 | |
""" | |
coeff = self._coeff / t._coeff | |
exponent = self._exponent.esub(t._exponent) | |
return self.__class__(self.parent(), coeff=coeff, exponent=exponent) | |
def _cmp_(self, other, i=None): | |
r""" | |
Compare this term with ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a._cmp_(a) | |
0 | |
""" | |
ov = other.valuation() | |
sv = self.valuation() | |
c = ov - sv | |
if c == 0 and self._exponent != other._exponent: | |
if ( | |
self.parent()._order.greatest_tuple(self._exponent, other._exponent) | |
== self._exponent | |
): | |
c = 1 | |
else: | |
c = -1 | |
return c | |
def same(self, t): | |
r""" | |
Test wether this term is the same as ``t``, meaning | |
it has the same coefficient and exponent. | |
This is not the same as equality. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a.same(a) | |
True | |
""" | |
return self._coeff == t._coeff and self._exponent == t._exponent | |
def __eq__(self, other): | |
r""" | |
Test quality of this term with ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a == a | |
True | |
sage: a == x.leading_term() | |
False | |
""" | |
return self._cmp_(other) == 0 | |
def __ne__(self, other): | |
r""" | |
Test inquality of this term with ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a != a | |
False | |
sage: a != x.leading_term() | |
True | |
""" | |
return not self == other | |
def __lt__(self, other): | |
r""" | |
Test if this term is less than ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a < b | |
False | |
""" | |
return self._cmp_(other) < 0 | |
def __gt__(self, other): | |
r""" | |
Test if this term is greater than ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a > b | |
True | |
""" | |
return self._cmp_(other) > 0 | |
def __le__(self, other): | |
r""" | |
Test if this term is less than or equal than ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a <= b | |
False | |
""" | |
return self._cmp_(other) <= 0 | |
def __ge__(self, other): | |
r""" | |
Test if this term is greater than or equal than ``other``. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a >= b | |
True | |
""" | |
return self._cmp_(other) >= 0 | |
def _repr_(self): | |
r""" | |
Return a string representing this term. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f | |
(1 + O(2^20))*y + (1 + O(2^20))*x*y + (2 + O(2^21))*x | |
""" | |
parent = self.parent() | |
if self._coeff._is_atomic() or (-self._coeff)._is_atomic(): | |
s = repr(self._coeff) | |
if s == "1": | |
s = "" | |
else: | |
s = "(%s)" % self._coeff | |
for i in range(parent._ngens): | |
if self._exponent[i] == 1: | |
s += "*%s" % parent._names[i] | |
elif self._exponent[i] > 1 or self._exponent[i] < 0: | |
s += "*%s^%s" % (parent._names[i], self._exponent[i]) | |
if s[0] == "*": | |
return s[1:] | |
else: | |
return s | |
class PolyCircleTermMonoid(Monoid_class, UniqueRepresentation): | |
Element = PolyCircleTerm | |
def __init__(self, parent_algebra): | |
names = parent_algebra.variable_names() | |
Monoid_class.__init__(self, names=names) | |
self._field = parent_algebra._field | |
self._names = names | |
self._ngens = len(names) | |
self._order = parent_algebra._order | |
self._parent_algebra = parent_algebra | |
self._log_radii = parent_algebra.log_radii() | |
def field(self): | |
r""" | |
Return the coefficient field of this term monoid. | |
This is the same as for the parent algebra. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: M.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this term monoid. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: M.prime() | |
2 | |
""" | |
return self._field.prime() | |
def parent_algebra(self): | |
r""" | |
Return the parent algebra of this term monoid. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: PA = M.parent_algebra() | |
""" | |
return self._parent_algebra | |
def generalized_order(self): | |
r""" | |
Return the generalized order used to break ties. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: M.generalized_order() | |
Generalized monomial order in 2 variables using (lex, min) | |
""" | |
return self._order | |
def variable_names(self): | |
r""" | |
Return the variables names of this term monoid. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: M.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def ngens(self): | |
r""" | |
Return the number of generators of this term monoid. | |
EXAMPLES:: | |
sage: A = PolyCircleAlgebra(Qp(2), (-1,-1), "x,y", prec=10 ) | |
sage: M = A.monoid_of_terms() | |
sage: M.ngens() | |
2 | |
""" | |
return self._ngens | |
def _repr_(self): | |
r""" | |
Return a string representation of this term monoid. | |
""" | |
return "Monoid of terms for poly-circle algebra" | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, we only coerce from coefficient ring. | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
else: | |
return False |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sage.rings.integer_ring import ZZ | |
from sage.modules.free_module_element import vector | |
from sage.rings.polynomial.term_order import TermOrder | |
from sage.matrix.constructor import matrix | |
from sage.structure.sage_object import SageObject | |
from sage.structure.element import CommutativeAlgebraElement | |
from sage.rings.polynomial.polydict import PolyDict | |
from sage.modules.free_module_element import vector | |
from sage.geometry.polyhedral_complex import Polyhedron | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.rings.infinity import Infinity | |
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing | |
from sage.structure.unique_representation import UniqueRepresentation | |
from sage.structure.parent import Parent | |
from sage.matrix.constructor import matrix | |
from sage.rings.integer_ring import ZZ | |
from sage.structure.category_object import normalize_names | |
from sage.categories.algebras import Algebras | |
from sage.modules.free_module_element import vector | |
from sage.geometry.polyhedral_complex import Polyhedron | |
from sage.geometry.fan import Fan | |
from sage.geometry.cone import Cone | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.rings.infinity import Infinity | |
from sage.plot.plot import plot | |
from sage.rings.infinity import Infinity | |
from sage.structure.element import MonoidElement | |
from sage.rings.polynomial.polydict import ETuple | |
from sage.monoids.monoid import Monoid_class | |
from sage.structure.unique_representation import UniqueRepresentation | |
class GeneralizedOrderPolyAnnulus(SageObject): | |
def __init__(self, n, cones, group_order="lex", score_function="norm"): | |
r""" | |
Create a generalized monomial order for a poly-annulus polyhedral algebra | |
in ``n`` varaibles with optional group order and score function. | |
INPUT: | |
- ``n`` -- the number of variables | |
- ``group_order`` (default: ``lex``) -- the name of a group order on `\ZZ^n`, choices are: "lex" | |
- ``score_function`` (default: ``norm``) -- the name of a score function, choices are: "norm" | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: GeneralizedOrderPolyAnnulus(2, cones) | |
Generalized monomial order for poly-annulus in 2 variables using (lex, norm) | |
""" | |
self._n = n | |
self._n_cones = 2**self._n | |
# Build cones | |
self._cones = cones | |
if group_order in ["lex"]: | |
self._group_order = TermOrder(name=group_order) | |
else: | |
raise ValueError("Available group order are: 'lex'") | |
# Set score function. Add more here. | |
if score_function == "norm": | |
self._score_function = norm_score_function | |
else: | |
raise ValueError("Available score function are: 'norm'") | |
# Store names | |
self._group_order_name = group_order | |
self._score_function_name = score_function | |
def _repr_(self): | |
r""" | |
TESTS:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: GeneralizedOrderPolyAnnulus(2,cones)._repr_() | |
'Generalized monomial order for poly-annulus in 2 variables using (lex, norm)' | |
""" | |
group = self._group_order_name | |
function = self._score_function_name | |
n = str(self._n) | |
return ( | |
"Generalized monomial order for poly-annulus in %s variables using (%s, %s)" | |
% (n, group, function) | |
) | |
def __hash__(self): | |
r""" | |
Return the hash of self. It depends on the number of variables, the group_order and the score function. | |
""" | |
return hash(self._group_order_name + self._score_function_name + str(self._n)) | |
def n_cones(self): | |
r""" | |
Return the number of cones (which is 2 to the power of the number of variables). | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.n_cones() | |
4 | |
""" | |
return self._n_cones | |
def cones(self): | |
r""" | |
Return the list of matrices containing the generators of the cones. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.cones() | |
[ | |
[1 0] [-1 0] [-1 0] [ 1 0] | |
[0 1], [ 0 -1], [ 0 1], [ 0 -1] | |
] | |
""" | |
return self._cones | |
def cone(self, i): | |
r""" | |
Return the matrix whose columns are the generators of the ``i``-th cone. | |
INPUT: | |
- `i` -- an integer, a cone index | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.cone(0) | |
[1 0] | |
[0 1] | |
""" | |
if i < 0 or i > self._n: | |
raise IndexError("cone index out of range") | |
return self._cones[i] | |
def group_order(self): | |
r""" | |
Return the underlying group order. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.group_order() | |
Lexicographic term order | |
""" | |
return self._group_order | |
def group_order_name(self): | |
r""" | |
Return the name of the underlying group order. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.group_order_name() | |
'lex' | |
""" | |
return self._group_order_name | |
def score_function_name(self): | |
r""" | |
Return the name of the underlying score function. | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.score_function_name() | |
'norm' | |
""" | |
return self._score_function_name | |
def score(self, t): | |
r""" | |
Compute the score of a tuple ``t``. | |
INPUT: | |
- `t` -- a tuple of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.score((-2,3)) | |
5 | |
""" | |
return self._score_function(t) | |
def compare(self, a, b): | |
r""" | |
Return 1, 0 or -1 whether tuple ``a`` is greater than, equal or less than to tuple ``b`` respectively. | |
INPUT: | |
- `a` and `b` -- two tuples of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.compare((1,2), (3,-4)) | |
-1 | |
""" | |
if a == b: | |
return 0 | |
diff = self._score_function(a) - self._score_function(b) | |
if diff != 0: | |
return 1 if diff > 0 else -1 | |
else: | |
return 1 if self._group_order.greater_tuple(a, b) == a else -1 | |
def greatest_tuple(self, *L): | |
r""" | |
Return the greatest tuple in ``L``. | |
INPUT: | |
- *L -- integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrderPolyAnnulus | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.greatest_tuple((1,-1),(2,-3),(3,-4)) | |
(3, -4) | |
""" | |
n = len(L) | |
if n == 0: | |
raise ValueError("empty list of tuples") | |
if n == 1: | |
return L[0] | |
else: | |
a = L[0] | |
b = self.greatest_tuple(*L[1:]) | |
return a if self.compare(a, b) == 1 else b | |
def translate_to_cone(self, i, L): | |
r""" | |
Return a tuple ``t`` such that `t + L` is contained in the ``i``-th cone. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L`` -- a list of integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.translate_to_cone(2, [(1,2),(-2,-3),(1,-4)]) | |
(-1, 4) | |
""" | |
cone_matrix = self._cones[i] | |
T = matrix(ZZ, [cone_matrix * vector(v) for v in L]) | |
return tuple(cone_matrix * vector([-min(0, *c) for c in T.columns()])) | |
def greatest_tuple_for_cone(self, i, *L): | |
r""" | |
Return the greatest tuple of the list of tuple `L` with respect to the `i`-th cone. | |
This is the unique tuple `t` in `L` such that each time the greatest tuple of `s + L` | |
for a tuple `s` is contained in the `i`-th cone, it is equal to `s + t`. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``L`` -- a list of integer tuples | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: L = [(1,2), (-2,-2), (-4,5), (5,-6)] | |
sage: t = order.greatest_tuple_for_cone(1, *L);t | |
(-2, -2) | |
We can check the result:: | |
sage: s = order.translate_to_cone(1, L) | |
sage: sL = [tuple(vector(s) + vector(l)) for l in L] | |
sage: tuple(vector(s) + vector(t)) == order.greatest_tuple(*sL) | |
True | |
""" | |
t = vector(self.translate_to_cone(i, L)) | |
L = [vector(l) for l in L] | |
return tuple(vector(self.greatest_tuple(*[tuple(t + l) for l in L])) - t) | |
def is_in_cone(self, i, t): | |
r""" | |
Test whether the tuple ``t`` is contained in the ``i``-th cone or not. | |
INPUT: | |
- ``i`` -- an integer, a cone index | |
- ``t`` -- a tuple of integers | |
EXAMPLES:: | |
sage: from sage.rings.polytopal.GeneralizedOrders import GeneralizedOrder | |
sage: cones = [] | |
sage: cones.append(matrix(ZZ,[[1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,-1]])) | |
sage: cones.append(matrix(ZZ,[[-1,0],[0,1]])) | |
sage: cones.append(matrix(ZZ,[[1,0],[0,-1]])) | |
sage: order = GeneralizedOrderPolyAnnulus(2, cones) | |
sage: order.is_in_cone(0, (1,2)) | |
True | |
sage: order.is_in_cone(0,(-2,3)) | |
False | |
""" | |
return all(c >= 0 for c in self.cone(i) * vector(t)) | |
def norm_score_function(t): | |
return sum([abs(c) for c in t]) | |
class PolyAnnulusAlgebraElement(CommutativeAlgebraElement): | |
def __init__(self, parent, x=None, prec=None): | |
CommutativeAlgebraElement.__init__(self, parent) | |
if isinstance(x, PolyAnnulusAlgebraElement): | |
self._poly = x._poly | |
if prec is None: | |
self._prec = x._prec | |
else: | |
self._prec = prec | |
elif isinstance(x, PolyAnnulusTerm): | |
self._poly = parent._polynomial_ring( | |
PolyDict({x.exponent(): parent._field(x.coefficient())}) | |
) | |
self._prec = Infinity | |
else: | |
try: | |
self._poly = parent._polynomial_ring(x) | |
if prec is None: | |
self._prec = Infinity | |
else: | |
self._prec = prec | |
except TypeError: | |
raise | |
def terms(self): | |
r""" | |
Return the terms of ``self`` in a list, sorted by decreasing order. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y + y^-1 + 1*x^-3 | |
sage: f.terms() | |
[(1 + O(2^20))*x^-3, | |
(1 + O(2^20))*x*y, | |
(1 + O(2^20))*y^-1, | |
(1 + O(2^20))*y, | |
(2 + O(2^21))*x] | |
""" | |
terms = [ | |
PolyAnnulusTerm(self.parent()._monoid_of_terms, coeff=c, exponent=e) | |
for e, c in self._poly.dict().items() | |
] | |
return sorted(terms, reverse=True) | |
def leading_term(self, i=None): | |
r""" | |
Return the leading term of this series if ``i`` is None, otherwise the | |
leading term for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term() | |
(1 + O(2^20))*x*y | |
sage: f.leading_term(2) | |
(1 + O(2^20))*y^-1 | |
""" | |
if i is None: | |
return self.terms()[0] | |
ini = self.initial(i)._poly | |
le = self.parent()._order.greatest_tuple_for_cone(i, *ini.exponents()) | |
return PolyAnnulusTerm(self.parent()._monoid_of_terms, ini[le], le) | |
def leading_monomial(self, i=None): | |
r""" | |
Return the leading monomial of this series if ``i`` is None, otherwise the | |
leading monomial for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_monomial() | |
(1 + O(2^20))*x*y | |
sage: f.leading_monomial(2) | |
(1 + O(2^20))*y^-1 | |
""" | |
return self.leading_term(i).monomial() | |
def leading_coefficient(self, i=None): | |
r""" | |
Return the leading coefficient of this series if ``i`` is None, otherwise the | |
leading coefficient for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_coefficient() | |
1 + O(2^20) | |
sage: f.leading_coefficient(2) | |
1 + O(2^20) | |
""" | |
return self.leading_term(i).coefficient() | |
def leadings(self, i=None): | |
r""" | |
Return a list containing the leading coefficient, monomial and term | |
of this series if ``i`` is None, or th same for the ``i``-th vertex otherwise. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leadings() | |
(1 + O(2^20), (1 + O(2^20))*x*y, (1 + O(2^20))*x*y) | |
""" | |
lt = self.leading_term(i) | |
return (lt.coefficient(), lt.monomial(), lt) | |
def initial(self, i=None): | |
r""" | |
Return the initial part of this series if ``i`` is None, otherwise | |
the initial part for the ``i``-the vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.initial() | |
(1 + O(2^20))*x*y | |
sage: f.initial(2) | |
(1 + O(2^20))*y^-1 | |
""" | |
terms = self.terms() | |
if i is None: | |
v = self.valuation() | |
else: | |
v = min([t.valuation(i) for t in terms]) | |
return sum( | |
[self.__class__(self.parent(), t) for t in terms if t.valuation(i) == v] | |
) | |
def valuation(self, i=None): | |
r""" | |
Return the valuation of this series if ``i`` is None | |
(which is the minimum over the valuations at each vertex), | |
otherwise the valuation for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.valuation() | |
-2 | |
""" | |
if self.is_zero(): | |
return Infinity | |
return self.leading_term(i).valuation(i) | |
def _normalize(self): | |
r""" | |
Normalize this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.add_bigoh(2) # Indirect doctest | |
(1 + O(2^4))*x*y + (1 + O(2^3))*y^-1 + (2 + O(2^3))*x + OO(2) | |
""" | |
if self._prec == Infinity: | |
return | |
terms = [] | |
for t in self.terms(): | |
exponent = t.exponent() | |
coeff = t.coefficient() | |
v = max( | |
[ | |
ETuple(tuple(vertex)).dotprod(exponent) | |
for vertex in self.parent().vertices() | |
] | |
) | |
if coeff.precision_absolute() > self._prec + v: | |
coeff = coeff.add_bigoh(self._prec + v) | |
if coeff.valuation() < self._prec + v: | |
t._coeff = coeff | |
terms.append(t) | |
self._poly = sum([self.__class__(self.parent(), t)._poly for t in terms]) | |
def add_bigoh(self, prec): | |
r""" | |
Return this series truncated to precision ``prec``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.add_bigoh(2) # Indirect doctest | |
(1 + O(2^4))*x*y + (1 + O(2^3))*y^-1 + (2 + O(2^3))*x + OO(2) | |
""" | |
return self.parent()(self, prec=prec) | |
def is_zero(self): | |
r""" | |
Test if this series is zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.is_zero() | |
False | |
sage: (f-f).is_zero() | |
True | |
""" | |
# self._normalize() | |
return self._poly == 0 | |
def __eq__(self, other): | |
r""" | |
Test equality of this series and ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = 3*x*y | |
sage: f == g | |
False | |
sage: f == f | |
True | |
""" | |
diff = self - other | |
return diff.is_zero() | |
def _add_(self, other): | |
r""" | |
Return the addition of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = 3*x*y | |
sage: f + g | |
(1 + O(2^20))*y^-1 + (2 + O(2^21))*x + (2^2 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly + other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _sub_(self, other): | |
r""" | |
Return the substraction of this series and ``other`. | |
The precision is adjusted to the min of the inputs precisions. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = -3*x*y | |
sage: f - g | |
(1 + O(2^20))*y^-1 + (2 + O(2^21))*x + (2^2 + O(2^20))*x*y | |
""" | |
prec = min(self._prec, other._prec) | |
ans = self.__class__(self.parent(), self._poly - other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this series and ``other`. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = 3*x*y | |
sage: f*g | |
(1 + 2 + O(2^20))*x^2*y^2 + (2 + 2^2 + O(2^21))*x^2*y + (1 + 2 + O(2^20))*x | |
""" | |
a = self.valuation() + other._prec | |
b = other.valuation() + self._prec | |
prec = min(a, b) | |
ans = self.__class__(self.parent(), self._poly * other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _div_(self, other): | |
r""" | |
Return the multiplication of this series and ``other`. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = x | |
sage: g = x*y | |
sage: f/g | |
(1 + O(2^20))*y^-1 | |
""" | |
prec = self._prec - other.valuation() | |
ans = self.__class__(self.parent(), self._poly / other._poly, prec=prec) | |
ans._normalize() | |
return ans | |
def _neg_(self): | |
r""" | |
Return the negation of this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = -x | |
sage: -f | |
(1 + O(2^20))*x | |
""" | |
ans = self.__class__(self.parent(), -self._poly, prec=self._prec) | |
ans._normalize() | |
return ans | |
def _repr_(self): | |
r""" | |
Return a string representation of this series. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: x | |
(1 + O(2^20))*x | |
""" | |
self._normalize() | |
terms = self.terms() | |
r = "" | |
for t in terms: | |
if t.valuation() < self._prec: | |
s = repr(t) | |
if r == "": | |
r += s | |
elif s[0] == "-": | |
r += " - " + s[1:] | |
else: | |
r += " + " + s | |
if not self._prec == Infinity: | |
if r: | |
r += " + " | |
r += f"OO({self._prec})" | |
return r | |
def leading_module_polyhedron(self, i=None, backend="normaliz"): | |
r""" | |
Return the polyhedron whose intger points are exactly the exponents of all | |
leadings terms of multiple of this series that lie in the restricted | |
``i``-th cone. | |
Is ``i`` is None, return a list with all polyhedron for all vertices. | |
The default backend for the polyhedron class is normaliz. It is needed | |
for the method least_common_multiples to retrieve integral generators. | |
If you only wan't to construct the polyhedron, any backend is ok. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_module_polyhedron(0) | |
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays | |
""" | |
if i is None: | |
return [ | |
self.leading_module_polyhedron(i, backend) | |
for i in range(self.parent()._nvertices) | |
] | |
vertices = self.parent()._vertices | |
ieqs = [] | |
shift = vector(self.leading_monomial(i).exponent()) | |
for j in [k for k in range(len(vertices)) if k != i]: | |
v = vertices[j] | |
a = tuple(vector(vertices[i]) - vector(v)) | |
c = self.valuation(i) - self.valuation(j) | |
if j < i: | |
c += 1 | |
ieqs.append((-c,) + a) | |
P1 = Polyhedron(ieqs=ieqs) | |
return Polyhedron( | |
rays=self.parent().polyhedron_at_vertex(i).rays(), | |
vertices=[list(vector(v) + shift) for v in P1.vertices()], | |
backend=backend, | |
) | |
def least_common_multiples(self, other, i): | |
r""" | |
Return the finite sets of monomials which are the lcms of this series and ``other`` | |
for the ``i``-th cone. | |
This method require the backend normaliz. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x - y | |
sage: f.least_common_multiples(g,0) | |
[(1 + O(2^20))*x^-1*y^-1, (1 + O(2^20))*y^-2] | |
""" | |
return [ | |
self.parent()._monoid_of_terms(1, exponent=tuple(e)) | |
for e in self.leading_module_polyhedron(i) | |
.intersection(other.leading_module_polyhedron(i)) | |
.integral_points_generators()[0] | |
] | |
def critical_pair(self, other, i, lcm): | |
r""" | |
Return the S-pair of this series and ``other`` for the ``i``-th | |
cone given a leading common multiple ``lcm``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y^-1 | |
sage: lcm = f.least_common_multiples(g,1)[0] | |
sage: f.critical_pair(g, 1, lcm) | |
(1 + 2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + 2^11 + 2^12 + 2^13 + 2^14 + 2^15 + 2^16 + 2^17 + 2^18 + 2^19 + O(2^20))*x^-1*y + (1 + O(2^20))*x^-1 + (2 + O(2^21))*y | |
""" | |
lcf, lmf, _ = self.leadings(i) | |
lcg, lmg, _ = other.leadings(i) | |
return lcg * lcm._divides(lmf) * self - lcf * lcm._divides(lmg) * other | |
def all_critical_pairs(self, other, i=None): | |
r""" | |
Return all S-pairs of this series and ``other`` for the ``i``-th cone, | |
or all S-pairs for all cones if ``i`` is None. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y^-1 | |
sage: f.all_critical_pairs(g,0) | |
[(1 + O(2^20))*y + (1 + O(2^20)), (1 + O(2^20))*x*y^-1 + (1 + O(2^20))*x] | |
""" | |
if i is None: | |
return [ | |
item | |
for j in range(self.parent()._nvertices) | |
for item in self.all_critical_pairs(other, j) | |
] | |
lcms = self.least_common_multiples(other, i) | |
return [self.critical_pair(other, i, lcm) for lcm in lcms] | |
class PolyAnnulusAlgebra(Parent, UniqueRepresentation): | |
r""" | |
Parent class for series with finite precision in a polyhedral algebra with power series converging on a poly-annulus. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
""" | |
Element = PolyAnnulusAlgebraElement | |
def __init__( | |
self, | |
field, | |
polyhedron, | |
names, | |
score_function="norm", | |
group_order="lex", | |
prec=10, | |
): | |
self._field = field | |
self.element_class = PolyAnnulusAlgebraElement | |
self._prec = prec | |
self._polyhedron = polyhedron | |
self._vertices = polyhedron.vertices() | |
self._nvertices = len(self._vertices) | |
self._names = normalize_names(-1, names) | |
self._polynomial_ring = LaurentPolynomialRing(field, names=names) | |
self._gens = [ | |
self.element_class(self, g, prec=Infinity) | |
for g in self._polynomial_ring.gens() | |
] | |
self._ngens = len(self._gens) | |
self._cones = self._build_cones() | |
self._order = GeneralizedOrderPolyAnnulus( | |
self._ngens, | |
self._cones, | |
score_function=score_function, | |
group_order=group_order, | |
) | |
self._monoid_of_terms = PolyAnnulusTermMonoid(self) | |
Parent.__init__(self, names=names, category=Algebras(self._field).Commutative()) | |
def _build_cones(self): | |
cones = [self.cone_at_vertex(i) for i in range(self._nvertices)] | |
decompo_cones = [] | |
for cone in cones: | |
m = matrix.zero(ZZ, self._ngens) | |
for i, ray in enumerate(cone.rays()): | |
m.set_column(i, vector(tuple(ray))) | |
decompo_cones.append(m) | |
return decompo_cones | |
def generalized_order(self): | |
r""" | |
Return the term order used to break ties. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.generalized_order() | |
Generalized monomial order for poly-annulus in 2 variables using (lex, norm) | |
""" | |
return self._order | |
def variable_names(self): | |
r""" | |
Return the variables names of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, there are no inter-algebras coercions, we only coerce from | |
the coefficient field or the corresponding term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x, y = A.gens() | |
sage: 2*x #indirect doctest | |
(2 + O(2^21))*x | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
elif isinstance(R, PolyAnnulusTermMonoid): | |
return True | |
else: | |
return False | |
def field(self): | |
r""" | |
Return the coefficient field of this algebra (currently restricted to Qp). | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this algebra. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.prime() | |
2 | |
""" | |
return self._field.prime() | |
def gen(self, n=0): | |
r""" | |
Return the ``n``-th generator of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.gen(1) | |
(1 + O(2^20))*y | |
""" | |
if n < 0 or n >= self._ngens: | |
raise IndexError("Generator index out of range") | |
return self._gens[n] | |
def gens(self): | |
r""" | |
Return the list of generators of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.gens() | |
[(1 + O(2^20))*x, (1 + O(2^20))*y] | |
""" | |
return self._gens | |
def ngens(self): | |
r""" | |
Return the number of generators of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.ngens() | |
2 | |
""" | |
return len(self._gens) | |
def zero(self): | |
r""" | |
Return the element 0 of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.zero() | |
""" | |
return self(0) | |
def polyhedron(self): | |
r""" | |
Return the defining polyhedron of this algebra. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.polyhedron() | |
A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices | |
""" | |
return self._polyhedron | |
def vertices(self): | |
r""" | |
Return the list of vertices of the defining polyhedron of this algebra. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.vertices() | |
(A vertex at (-1, -1), | |
A vertex at (-1, 1), | |
A vertex at (1, -1), | |
A vertex at (1, 1)) | |
""" | |
return self._vertices | |
def monoid_of_terms(self): | |
r""" | |
Return the monoid of terms for this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.monoid_of_terms() | |
monoid of terms | |
""" | |
return self._monoid_of_terms | |
def vertex(self, i=0, etuple=False): | |
r""" | |
Return the ``i``-th vertex of the defining polyhedron (indexing starts at zero). | |
The flag ``etuple`` indicates whether the result should be returned as an ``ETuple``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.vertex(0) | |
A vertex at (-1, -1) | |
sage: A.vertex(1, etuple=True) | |
(-1, 1) | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
if etuple: | |
return ETuple(tuple(self.vertex(i))) | |
return self._vertices[i] | |
def vertex_indices(self): | |
r""" | |
Return the list of verex indices. Indexing starts at zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.vertex_indices() | |
[0, 1, 2, 3] | |
""" | |
return [i for i in range(self._nvertices)] | |
def cone_at_vertex(self, i=0): | |
r""" | |
Return the cone for the ``i``-th vertex of this algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: C = A.cone_at_vertex(0); C | |
2-d cone in 2-d lattice N | |
sage: C.rays() | |
N( 0, -1), | |
N(-1, 0) | |
in 2-d lattice N | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
return Cone(self.polyhedron_at_vertex(i)) | |
def polyhedron_at_vertex(self, i=0): | |
r""" | |
Return the the cone for the ``i``-th vertex as a polyhedron. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: C = A.polyhedron_at_vertex(0); C | |
A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays | |
""" | |
if i < 0 or i >= self._nvertices: | |
raise IndexError("Vertex index out of range") | |
ieqs = [] | |
for v in self._vertices[:i] + self._vertices[i + 1 :]: | |
a = tuple(vector(self._vertices[i]) - vector(v)) | |
ieqs.append((0,) + a) | |
return Polyhedron(ieqs=ieqs) | |
def plot_leading_monomials(self, G): | |
r""" | |
Experimental. Plot in the same graphics all polyhedrons containing | |
the leading monomials of the series in the list ``G``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: A.plot_leading_monomials([2*x + y, x**2 - 3*y**3]) | |
Graphics object consisting of 35 graphics primitives | |
""" | |
plots = [] | |
for g in G: | |
plots += [plot(p) for p in g.leading_module_polyhedron()] | |
return sum(plots) | |
def fan(self): | |
r""" | |
Return the fan whose maximal cones are the cones at each vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: A.fan() | |
Rational polyhedral fan in 2-d lattice N | |
""" | |
cones = [] | |
for i in range(len(self._vertices)): | |
cones.append(Cone(self.cone_at_vertex(i))) | |
return Fan(cones=cones) | |
class PolyAnnulusTerm(MonoidElement): | |
def __init__(self, parent, coeff, exponent=None): | |
MonoidElement.__init__(self, parent) | |
field = parent._field | |
if isinstance(coeff, PolyAnnulusTerm): | |
if coeff.parent().variable_names() != self.parent().variable_names(): | |
raise ValueError("the variable names do not match") | |
self._coeff = field(coeff._coeff) | |
self._exponent = coeff._exponent | |
else: | |
self._coeff = field(coeff) | |
if self._coeff.is_zero(): | |
raise TypeError("a term cannot be zero") | |
self._exponent = ETuple([0] * parent.ngens()) | |
if exponent is not None: | |
if not isinstance(exponent, ETuple): | |
exponent = ETuple(exponent) | |
self._exponent = self._exponent.eadd(exponent) | |
if len(self._exponent) != parent.ngens(): | |
raise ValueError( | |
"the length of the exponent does not match the number of variables" | |
) | |
def coefficient(self): | |
r""" | |
Return the coefficient of this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().coefficient() | |
1 + O(2^20) | |
""" | |
return self._coeff | |
def exponent(self): | |
r""" | |
Return the exponent of this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().exponent() | |
(1, 1) | |
""" | |
return self._exponent | |
def valuation(self, i=None, vertex_index=False): | |
r""" | |
Return the valuation of this term if ``i`` is None | |
(which is the minimum over the valuations at each vertex), | |
otherwise the valuation for the ``i``-th vertex. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().valuation() | |
-2 | |
""" | |
if self._coeff == 0: | |
return Infinity | |
if i is None: | |
m = min([(self.valuation(j), j) for j in self.parent().vertex_indices()]) | |
if vertex_index: | |
return m | |
else: | |
return m[0] | |
return self._coeff.valuation() - self._exponent.dotprod( | |
self.parent().vertex(i, etuple=True) | |
) | |
def monomial(self): | |
r""" | |
Return this term divided by its coefficient. x. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: f.leading_term().monomial() | |
(1 + O(2^20))*x*y | |
""" | |
coeff = self.parent()._field(1) | |
exponent = self._exponent | |
return self.__class__(self.parent(), coeff, exponent) | |
def _mul_(self, other): | |
r""" | |
Return the multiplication of this term by ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y | |
sage: f.leading_term()*g.leading_term() | |
(1 + O(2^20))*x*y^2 | |
""" | |
coeff = self._coeff * other._coeff | |
exponent = self._exponent.eadd(other._exponent) | |
return self.__class__(self.parent(), coeff, exponent) | |
def _to_poly(self): | |
r""" | |
Return this term as a polynomial. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: type(f.leading_term()._to_poly()) | |
<class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> | |
""" | |
R = self.parent()._parent_algebra._polynomial_ring | |
return self._coeff * R.monomial(self._exponent) | |
def _divides(self, t): | |
r""" | |
Return this term divided by ``t``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: g = x + y | |
sage: a = f.leading_term() | |
sage: b = g.leading_term() | |
sage: a._divides(b) | |
(1 + O(2^20))*x | |
""" | |
coeff = self._coeff / t._coeff | |
exponent = self._exponent.esub(t._exponent) | |
return self.__class__(self.parent(), coeff=coeff, exponent=exponent) | |
def _cmp_(self, other, i=None): | |
r""" | |
Compare this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a._cmp_(a) | |
0 | |
""" | |
ov, oi = other.valuation(vertex_index=True) | |
sv, si = self.valuation(vertex_index=True) | |
c = ov - sv | |
if c == 0: | |
c = oi - si | |
if c == 0 and self._exponent != other._exponent: | |
if ( | |
self._order.greatest_tuple(self._exponent, other._exponent) | |
== self._exponent | |
): | |
c = 1 | |
else: | |
c = -1 | |
return c | |
def same(self, t): | |
r""" | |
Test wether this termù is the same as ``t``, meaning | |
it has the same coefficient and exponent. | |
This is not the same as equality. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a.same(a) | |
True | |
""" | |
return self._coeff == t._coeff and self._exponent == t._exponent | |
def __eq__(self, other): | |
r""" | |
Test quality of this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a == a | |
True | |
sage: a == x.leading_term() | |
False | |
""" | |
return self._cmp_(other) == 0 | |
def __ne__(self, other): | |
r""" | |
Test inquality of this term with ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: a != a | |
False | |
sage: a != x.leading_term() | |
True | |
""" | |
return not self == other | |
def __lt__(self, other): | |
r""" | |
Test if this term is less than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a < b | |
False | |
""" | |
return self._cmp_(other) < 0 | |
def __gt__(self, other): | |
r""" | |
Test if this term is greater than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a > b | |
True | |
""" | |
return self._cmp_(other) > 0 | |
def __le__(self, other): | |
r""" | |
Test if this term is less than or equal than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a <= b | |
False | |
""" | |
return self._cmp_(other) <= 0 | |
def __ge__(self, other): | |
r""" | |
Test if this term is greater than or equal than ``other``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y"); x,y = A.gens() | |
sage: f = 2*x + y^-1 + x*y | |
sage: a = f.leading_term() | |
sage: b = x.leading_term() | |
sage: a >= b | |
True | |
""" | |
return self._cmp_(other) >= 0 | |
def _repr_(self): | |
r""" | |
Return a string representing this term. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(-2,-1),(-1,-2)], rays=[(-1,0),(0,-1)]) | |
sage: A = PositiveExponentsAlgebra(Qp(2),P,"x,y"); x,y = A.gens() | |
sage: f = 2*x + y + x*y | |
sage: f | |
(1 + O(2^20))*y + (2 + O(2^21))*x + (1 + O(2^20))*x*y | |
""" | |
parent = self.parent() | |
if self._coeff._is_atomic() or (-self._coeff)._is_atomic(): | |
s = repr(self._coeff) | |
if s == "1": | |
s = "" | |
else: | |
s = "(%s)" % self._coeff | |
for i in range(parent._ngens): | |
if self._exponent[i] == 1: | |
s += "*%s" % parent._names[i] | |
elif self._exponent[i] > 1 or self._exponent[i] < 0: | |
s += "*%s^%s" % (parent._names[i], self._exponent[i]) | |
if s[0] == "*": | |
return s[1:] | |
else: | |
return s | |
class PolyAnnulusTermMonoid(Monoid_class, UniqueRepresentation): | |
Element = PolyAnnulusTerm | |
def __init__(self, parent_algebra): | |
names = parent_algebra.variable_names() | |
Monoid_class.__init__(self, names=names) | |
self._field = parent_algebra._field | |
self._names = names | |
self._ngens = len(names) | |
self._vertices = parent_algebra._vertices | |
self._nvertices = parent_algebra._nvertices | |
self._order = parent_algebra._order | |
self._parent_algebra = parent_algebra | |
def _coerce_map_from_(self, R): | |
r""" | |
Currently, we only coerce from coefficient ring. | |
""" | |
if self._field.has_coerce_map_from(R): | |
return True | |
else: | |
return False | |
def _repr_(self): | |
r""" | |
Return a string representation of this term monoid. | |
""" | |
return "monoid of terms" | |
def vertex_indices(self): | |
r""" | |
Return the list of verex indices. Indexing starts at zero. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.vertex_indices() | |
[0, 1, 2, 3] | |
""" | |
return [i for i in range(self._nvertices)] | |
def field(self): | |
r""" | |
Return the coefficient field of this term monoid. | |
This is the same as for the parent algebra. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.field() | |
2-adic Field with capped relative precision 20 | |
""" | |
return self._field | |
def prime(self): | |
r""" | |
Return the prime number of this term monoid. This | |
is the prime of the coefficient field. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.prime() | |
2 | |
""" | |
return self._field.prime() | |
def parent_algebra(self): | |
r""" | |
Return the parent algebra of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: PA = M.parent_algebra() | |
""" | |
return self._parent_algebra | |
def generalized_order(self): | |
r""" | |
Return the term order used to break ties. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.generalized_order() | |
Generalized monomial order for poly-annulus in 2 variables using (lex, norm) | |
""" | |
return self._order | |
def variable_names(self): | |
r""" | |
Return the variables names of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.variable_names() | |
('x', 'y') | |
""" | |
return self._names | |
def vertices(self): | |
r""" | |
Return the list of vertices of the defining polyhedron of the parent algebra | |
of this term monoid. | |
EXAMPLES: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.vertices() | |
(A vertex at (-1, -1), | |
A vertex at (-1, 1), | |
A vertex at (1, -1), | |
A vertex at (1, 1)) | |
""" | |
return self._vertices | |
def vertex(self, i=0, etuple=False): | |
r""" | |
Return the ``i``-th vertex of the defining polyhedron (indexing starts at zero) | |
of the parent algebra. | |
The flag ``etuple`` indicates whether the result should be returned as an ``ETuple``. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.vertex(0) | |
A vertex at (-1, -1) | |
sage: M.vertex(1, etuple=True) | |
(-1, 1) | |
""" | |
return self._parent_algebra.vertex(i, etuple=etuple) | |
def ngens(self): | |
r""" | |
Return the number of generators of this term monoid. | |
EXAMPLES:: | |
sage: P = Polyhedron(vertices=[(1,1), (1,-1), (-1,-1), (-1,1)]) | |
sage: A = PolyAnnulusAlgebra(Qp(2), P, "x,y") | |
sage: M = A.monoid_of_terms() | |
sage: M.ngens() | |
2 | |
""" | |
return self._ngens |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment