Skip to content

Commit

Permalink
Trac #28574: conversion of nested polynomial rings to Macaulay2
Browse files Browse the repository at this point in the history
This ticket implements conversion to and from Macaulay2 of polynomial
rings over arbitrary base rings – nested polynomial rings in particular
– as well as their elements.

This ticket also implements `_macaulay2_()` for polydicts. This is used
in elements of nested polynomial rings, for example.

It also fixes an issue where constant polynomials are accidentally
converted to elements of the base ring in Macaulay2, not to elements of
the polynomial ring.

We add a special case in the conversion of Galois fields, since in
Macaulay2 it is more natural to define finite fields as `ZZ/p` rather
than `GF p`. This has a positive effect on performance, and simplifies
the construction of Macaulay2 polynomial rings.

URL: https://trac.sagemath.org/28574
Reported by: gh-mwageringel
Ticket author(s): Markus Wageringel
Reviewer(s): Franco Saliola, Dima Pasechnik
  • Loading branch information
Release Manager committed Nov 5, 2019
2 parents 3145f53 + ac2ff35 commit 75294da
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 58 deletions.
62 changes: 27 additions & 35 deletions src/sage/interfaces/macaulay2.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,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 |
"""
return self.new(_macaulay2_input_ring(base_ring, vars, order))
return self.new(self._macaulay2_input_ring(base_ring, vars, order))

def help(self, s):
"""
Expand Down Expand Up @@ -792,39 +792,25 @@ def new_from(self, type, value):
value = self(value)
return self.new("new %s from %s"%(type.name(), value.name()))

def _macaulay2_input_ring(self, base_ring, vars, order='GRevLex'):
"""
Build a string representation of a polynomial ring which can be used as
Macaulay2 input.
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::
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)
sage: R = GF(101)['x']
sage: macaulay2._macaulay2_input_ring(R.base_ring(), R.gens(), 'Lex') # optional - macaulay2
'sage...[symbol x, MonomialSize=>16, MonomialOrder=>Lex]'
"""
if not isinstance(base_ring, string_types):
base_ring = self(base_ring).name()

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)
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
Expand Down Expand Up @@ -1358,6 +1344,14 @@ def _sage_(self):
sage: macaulay2(S).sage() == S # optional - macaulay2
True
sage: R = GF(13)['a,b']['c,d']
sage: macaulay2(R).sage() == R # optional - macaulay2
True
sage: macaulay2('a^2 + c').sage() == R('a^2 + c') # optional - macaulay2
True
sage: macaulay2.substitute('a', R).sage().parent() is R # optional - macaulay2
True
sage: R = macaulay2("QQ^2") # optional - macaulay2
sage: R.sage() # optional - macaulay2
Vector space of dimension 2 over Rational Field
Expand Down Expand Up @@ -1475,7 +1469,7 @@ def _sage_(self):
gens = str(self.gens().toString())[1:-1]

# Check that we are dealing with default degrees, i.e. 1's.
if self.degrees().any("x -> x != {1}")._sage_():
if self.options().sharp("Degrees").any("x -> x != {1}")._sage_():
raise ValueError("cannot convert Macaulay2 polynomial ring with non-default degrees to Sage")
#Handle the term order
external_string = self.external_string()
Expand Down Expand Up @@ -1563,9 +1557,7 @@ def _sage_(self):
parent = m2_parent._sage_()

if cls_cls_str in ("PolynomialRing", "QuotientRing"):
from sage.misc.sage_eval import sage_eval
gens_dict = parent.gens_dict()
return sage_eval(self.external_string(), gens_dict)
return parent(self.external_string())
elif cls_cls_str == "Module":
entries = self.entries()._sage_()
return parent._element_constructor_(entries)
Expand Down
22 changes: 14 additions & 8 deletions src/sage/rings/finite_rings/finite_field_base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,20 @@ cdef class FiniteField(Field):

def _macaulay2_init_(self, macaulay2=None):
"""
Returns the string representation of ``self`` that Macaulay2 can
understand.
Return the string representation of this finite field that Macaulay2
can understand.
EXAMPLES::
Note that, in the case of a prime field, this returns ``ZZ/p`` instead
of the Galois field ``GF p``, since computations in polynomial rings
over ``ZZ/p`` are faster in Macaulay2 (as of 2019).
sage: GF(97,'a')._macaulay2_init_()
'GF(97,Variable=>symbol x)'
EXAMPLES::
sage: macaulay2(GF(97, 'a')) # optional - macaulay2
GF 97
sage: macaulay2(GF(49, 'a')) # optional - macaulay2
sage: macaulay2(GF(97, 'a')) # indirect doctest, optional - macaulay2
ZZ
--
97
sage: macaulay2(GF(49, 'a')) # indirect doctest, optional - macaulay2
GF 49
TESTS:
Expand All @@ -266,9 +269,12 @@ cdef class FiniteField(Field):
sage: K._sage_() # optional - macaulay2
Finite Field in b of size 7^2
"""
if self.is_prime_field():
return "ZZ/%s" % self.order()
return "GF(%s,Variable=>symbol %s)" % (self.order(),
self.variable_name())


def _sage_input_(self, sib, coerced):
r"""
Produce an expression which will reproduce this value when evaluated.
Expand Down
24 changes: 24 additions & 0 deletions src/sage/rings/polynomial/multi_polynomial_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,30 @@ def _repr_with_changed_varnames(self, varnames):
return self.element().poly_repr(varnames,
atomic_coefficients=atomic, sortkey=key)

def _macaulay2_(self, macaulay2=None):
"""
EXAMPLES::
sage: R = GF(13)['a,b']['c,d']
sage: macaulay2(R('a^2 + c')) # optional - macaulay2
2
c + a
TESTS:
Elements of the base ring are coerced to the polynomial ring
correctly::
sage: macaulay2(R('a^2')).ring()._operator('===', R) # optional - macaulay2
true
"""
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
m2_parent = macaulay2(self.parent())
macaulay2.use(m2_parent)
return macaulay2('substitute(%s,%s)' % (repr(self), m2_parent._name))

def degrees(self):
r"""
Returns a tuple (precisely - an ``ETuple``) with the
Expand Down
26 changes: 18 additions & 8 deletions src/sage/rings/polynomial/multi_polynomial_libsingular.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1194,12 +1194,13 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base):
"""
EXAMPLES::
sage: PolynomialRing(QQ, 'x', 2, order='deglex')._macaulay2_init_()
'QQ[symbol x0,symbol x1, MonomialSize=>16, MonomialOrder=>GLex]'
sage: PolynomialRing(QQ, 'x', 2, order='deglex')._macaulay2_init_() # optional - macaulay2
'sage...[symbol x0,symbol x1, MonomialSize=>16, MonomialOrder=>GLex]'
"""
from sage.interfaces.macaulay2 import _macaulay2_input_ring
return _macaulay2_input_ring(self.base_ring(), self.gens(),
self.term_order().macaulay2_str())
if macaulay2 is None:
macaulay2 = macaulay2_default
return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens(),
self.term_order().macaulay2_str())

def _singular_(self, singular=singular_default):
"""
Expand Down Expand Up @@ -5000,9 +5001,9 @@ cdef class MPolynomial_libsingular(MPolynomial):

return new_MP(self._parent, p_Minus_mm_Mult_qq(p_Copy(self._poly, r), m._poly, q._poly, r))

def _macaulay2_(self, macaulay2=macaulay2):
def _macaulay2_(self, macaulay2=macaulay2_default):
"""
Return a Macaulay2 string representation of this polynomial.
Return a Macaulay2 element corresponding to this polynomial.
.. NOTE::
Expand All @@ -5029,10 +5030,19 @@ cdef class MPolynomial_libsingular(MPolynomial):
x^21 + 2*x^7*y^14
sage: R(h^20) == f^20 # optional - macaulay2
True
TESTS:
Check that constant polynomials are coerced to the polynomial ring, not
the base ring (:trac:`28574`)::
sage: R = QQ['x,y']
sage: macaulay2(R('4')).ring()._operator('===', R) # optional - macaulay2
true
"""
m2_parent = macaulay2(self.parent())
macaulay2.use(m2_parent)
return macaulay2(repr(self))
return macaulay2('substitute(%s,%s)' % (repr(self), m2_parent._name))

def add_m_mul_q(self, MPolynomial_libsingular m, MPolynomial_libsingular q):
"""
Expand Down
12 changes: 7 additions & 5 deletions src/sage/rings/polynomial/multi_polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ def _macaulay2_init_(self, macaulay2=None):
"""
EXAMPLES::
sage: PolynomialRing(QQ, 'x', 2, implementation='generic')._macaulay2_init_()
'QQ[symbol x0,symbol x1, MonomialSize=>16, MonomialOrder=>GRevLex]'
sage: PolynomialRing(QQ, 'x', 2, implementation='generic')._macaulay2_init_() # optional - macaulay2
'sage...[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())
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
return macaulay2._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
6 changes: 4 additions & 2 deletions src/sage/rings/polynomial/polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -933,8 +933,10 @@ def _macaulay2_init_(self, macaulay2=None):
sage: macaulay2(R) is macaulay2(R) # optional - macaulay2
True
"""
from sage.interfaces.macaulay2 import _macaulay2_input_ring
return _macaulay2_input_ring(self.base_ring(), self.gens())
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens())


def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None):
Expand Down

0 comments on commit 75294da

Please sign in to comment.