Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
28074: refactor caching of Macaulay2 polynomial rings
Browse files Browse the repository at this point in the history
This adds caching to univariate Macaulay2 rings and fixes a use of cached
Macaulay2 rings when converting ideals.

This also moves `is_exact()` from MPolynomialRing_macaulay2_repr to
MPolynomialRing_base.
  • Loading branch information
mwageringel authored and dimpase committed Sep 18, 2019
1 parent be66263 commit 5709e61
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 84 deletions.
55 changes: 42 additions & 13 deletions src/sage/interfaces/macaulay2.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,22 +601,20 @@ def ideal(self, *gens):

def ring(self, base_ring='ZZ', vars='[x]', order='Lex'):
r"""
Create a Macaulay2 ring.
Create a Macaulay2 polynomial ring.
INPUT:
- base_ring -- base ring (see examples below)
- vars -- a tuple or string that defines the variable names
- order -- string -- the monomial order (default: 'Lex')
- ``base_ring`` -- base ring (see examples below)
- ``vars`` -- a tuple or string that defines the variable names
- ``order`` -- string (default: 'Lex'); the monomial order
OUTPUT:
- a Macaulay2 ring (with base ring ZZ)
OUTPUT: a Macaulay2 ring
EXAMPLES:
This is a ring in variables named a through d over the finite field
of order 7, with graded reverse lex ordering::
This is a ring in variables named ``a`` through ``d`` over the finite
field of order 7, with graded reverse lex ordering::
sage: R1 = macaulay2.ring('ZZ/7', '[a..d]', 'GRevLex') # optional - macaulay2
sage: R1.describe() # optional - macaulay2
Expand Down Expand Up @@ -644,10 +642,7 @@ def ring(self, base_ring='ZZ', vars='[x]', order='Lex'):
sage: macaulay2.ring('QQ', '[a_0..a_2,b..<d,f]').vars() # optional - macaulay2
| a_0 a_1 a_2 b c f |
"""
varstr = str(vars)[1:-1]
r = re.compile(r"(?<=,)|(?<=\.\.<)|(?<=\.\.)(?!<)")
varstr = "symbol " + r.sub("symbol ", varstr)
return self.new('%s[%s, MonomialSize=>16, MonomialOrder=>%s]'%(base_ring, varstr, order))
return self.new(_macaulay2_input_ring(base_ring, vars, order))

def help(self, s):
"""
Expand Down Expand Up @@ -734,6 +729,40 @@ def new_from(self, type, value):
return self.new("new %s from %s"%(type.name(), value.name()))


def _macaulay2_input_ring(base_ring, vars, order='GRevLex'):
"""
Build a string representation of a polynomial ring which can be used as
Macaulay2 input.
TESTS::
sage: R = GF(101)['x']
sage: from sage.interfaces.macaulay2 import _macaulay2_input_ring
sage: _macaulay2_input_ring(R.base_ring(), R.gens(), 'Lex')
'ZZ/101[symbol x, MonomialSize=>16, MonomialOrder=>Lex]'
"""
if not isinstance(base_ring, string_types):
from sage.rings.integer_ring import is_IntegerRing
if base_ring.is_prime_field():
if base_ring.characteristic() == 0:
base_ring = "QQ"
else:
# Note that we explicitly use ZZ/p, since computations are
# faster than with GF p in Macaulay2 (2019).
base_ring = "ZZ/" + str(base_ring.characteristic())
elif is_IntegerRing(base_ring):
base_ring = "ZZ"
else:
raise TypeError("no conversion of %s to a Macaulay2 ring defined"
% base_ring)

varstr = str(vars)[1:-1].rstrip(',')
r = re.compile(r"(?<=,)|(?<=\.\.<)|(?<=\.\.)(?!<)")
varstr = "symbol " + r.sub("symbol ", varstr)
return '%s[%s, MonomialSize=>16, MonomialOrder=>%s]' % (base_ring, varstr,
order)


@instancedoc
class Macaulay2Element(ExtraTabCompletion, ExpectElement):
"""
Expand Down
16 changes: 14 additions & 2 deletions src/sage/rings/polynomial/multi_polynomial_ideal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2962,8 +2962,20 @@ def _macaulay2_(self, macaulay2=None):
sage: macaulay2(I) # optional - macaulay2
2 2 2
ideal (x*y - z , y - w )
TESTS:
Check that a cached base ring is used (:trac:`28074`)::
sage: R.<x,y> = QQ[]
sage: R1 = macaulay2(R) # optional - macaulay2
sage: _ = macaulay2('ZZ[x,y]') # optional - macaulay2
sage: R2 = macaulay2(R.ideal(y^2 - x)).ring() # optional - macaulay2
sage: R1._operator('===', R2) # optional - macaulay2
true
"""
if macaulay2 is None: macaulay2 = macaulay2_default
if macaulay2 is None:
macaulay2 = macaulay2_default
try:
I = self.__macaulay2[macaulay2]
I._check_valid()
Expand All @@ -2976,7 +2988,7 @@ def _macaulay2_(self, macaulay2=None):
pass

R = self.ring()
R._macaulay2_set_ring(macaulay2)
macaulay2.use(R._macaulay2_(macaulay2))

gens = [repr(x) for x in self.gens()]
if len(gens) == 0:
Expand Down
33 changes: 7 additions & 26 deletions src/sage/rings/polynomial/multi_polynomial_libsingular.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1168,38 +1168,19 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base):
R._check_valid()
return R
except (AttributeError, ValueError):
self.__macaulay2 = self._macaulay2_set_ring(macaulay2)
self.__macaulay2 = macaulay2(self._macaulay2_init_())
return self.__macaulay2

def _macaulay2_set_ring(self, macaulay2=macaulay2_default):
def _macaulay2_init_(self):
"""
Set the associated M2 ring.
INPUT:
- ``macaulay2`` - M2 instance
EXAMPLES::
sage: P.<x,y> = PolynomialRing(QQ)
sage: M2 = P._macaulay2_set_ring() # optional - macaulay2
sage: PolynomialRing(QQ, 'x', 2, order='deglex')._macaulay2_init_()
'QQ[symbol x0,symbol x1, MonomialSize=>16, MonomialOrder=>GLex]'
"""
if not self.__m2_set_ring_cache is None:
base_str, gens, order = self.__m2_set_ring_cache
else:
if self.base_ring().is_prime_field():
if self.characteristic() == 0:
base_str = "QQ"
else:
base_str = "ZZ/" + str(self.characteristic())
elif is_IntegerRing(self.base_ring()):
base_str = "ZZ"
else:
raise TypeError("no conversion of to a Macaulay2 ring defined")
gens = str(self.gens())
order = self.term_order().macaulay2_str()
self.__m2_set_ring_cache = (base_str, gens, order)
return macaulay2.ring(base_str, gens, order)
from sage.interfaces.macaulay2 import _macaulay2_input_ring
return _macaulay2_input_ring(self.base_ring(), self.gens(),
self.term_order().macaulay2_str())

def _singular_(self, singular=singular_default):
"""
Expand Down
45 changes: 10 additions & 35 deletions src/sage/rings/polynomial/multi_polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@
from sage.rings.ring import IntegralDomain
import sage.rings.fraction_field_element as fraction_field_element

from sage.rings.integer_ring import is_IntegerRing

import sage.rings.polynomial.multi_polynomial_ideal as multi_polynomial_ideal

from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base, is_MPolynomialRing
Expand All @@ -76,48 +74,25 @@
from sage.rings.polynomial.term_order import TermOrder

from sage.interfaces.singular import is_SingularElement
from sage.interfaces.all import macaulay2 as macaulay2_default
from sage.interfaces.macaulay2 import is_Macaulay2Element
from sage.libs.pari.all import pari_gen

from sage.structure.element import Element

class MPolynomialRing_macaulay2_repr:
"""
A mixin class for polynomial rings that support conversion to Macaulay2.
"""
def _macaulay2_(self, macaulay2=None):
if macaulay2 is None:
macaulay2 = macaulay2_default
try:
R = self.__macaulay2
if not (R.parent() is macaulay2):
raise ValueError
R._check_valid()
return R
except (AttributeError, ValueError):
base_str = self._macaulay2_base_str()
self.__macaulay2 = macaulay2.ring(base_str, str(self.gens()), \
self.term_order().macaulay2_str())
return self.__macaulay2

def _macaulay2_base_str(self):
if self.base_ring().is_prime_field():
if self.characteristic() == 0:
return "QQ"
else:
return "ZZ/" + str(self.characteristic())
elif is_IntegerRing(self.base_ring()):
return "ZZ"
else:
raise TypeError("no conversion of to a Macaulay2 ring defined")

def _macaulay2_set_ring(self, macaulay2):
macaulay2.ring(self._macaulay2_base_str(), str(self.gens()), \
self.term_order().macaulay2_str())
def _macaulay2_init_(self):
"""
EXAMPLES::
def is_exact(self):
return self.base_ring().is_exact()
sage: PolynomialRing(QQ, 'x', 2, implementation='generic')._macaulay2_init_()
'QQ[symbol x0,symbol x1, MonomialSize=>16, MonomialOrder=>GRevLex]'
"""
from sage.interfaces.macaulay2 import _macaulay2_input_ring
return _macaulay2_input_ring(self.base_ring(), self.gens(),
self.term_order().macaulay2_str())


class MPolynomialRing_polydict( MPolynomialRing_macaulay2_repr, PolynomialRing_singular_repr, MPolynomialRing_base):
Expand Down
14 changes: 14 additions & 0 deletions src/sage/rings/polynomial/multi_polynomial_ring_base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,20 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing):
return 'PolynomialRing(%s,[%s])'%(gap(self.base_ring()).name(),','.join(L))
return 'PolynomialRing(%s,[%s])'%(self.base_ring()._gap_init_(),','.join(L))

cpdef bint is_exact(self) except -2:
"""
Test whether this multivariate polynomial ring is defined over an exact
base ring.
EXAMPLES::
sage: PolynomialRing(QQ, 2, 'x').is_exact()
True
sage: PolynomialRing(RDF, 2, 'x').is_exact()
False
"""
return self.base_ring().is_exact()

def is_field(self, proof = True):
"""
Test whether this multivariate polynomial ring is a field.
Expand Down
20 changes: 12 additions & 8 deletions src/sage/rings/polynomial/polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,24 +913,28 @@ def _sage_input_(self, sib, coerced):
return sib.parent_with_gens(self, sie, self.variable_names(), 'R',
gens_syntax=gens_syntax)

def _macaulay2_(self, m2=None):
def _macaulay2_init_(self):
"""
EXAMPLES::
sage: R = QQ['x']
sage: macaulay2(R).describe() # optional - macaulay2
QQ[x, Degrees => {1}, Heft => {1}, MonomialOrder => {MonomialSize => 32},
QQ[x, Degrees => {1}, Heft => {1}, MonomialOrder => {MonomialSize => 16},
{GRevLex => {1} }
{Position => Up }
--------------------------------------------------------------------------------
DegreeRank => 1]
TESTS:
Check that results are cached (:trac:`28074`)::
sage: R = ZZ['t']
sage: macaulay2(R) is macaulay2(R) # optional - macaulay2
True
"""
if m2 is None:
import sage.interfaces.macaulay2
m2 = sage.interfaces.macaulay2.macaulay2
base_ring = m2( self.base_ring() )
var = self.gen()
return m2("%s[symbol %s]"%(base_ring.name(), var))
from sage.interfaces.macaulay2 import _macaulay2_input_ring
return _macaulay2_input_ring(self.base_ring(), self.gens())


def _is_valid_homomorphism_(self, codomain, im_gens):
Expand Down

0 comments on commit 5709e61

Please sign in to comment.