Skip to content

Commit

Permalink
Trac #28566: improve conversions between Macaulay2 and Sage
Browse files Browse the repository at this point in the history
This ticket implements and improves conversions between Macaulay2 and
Sage:

• vectors/free module elements

• matrices: The function `InterfaceElement._matrix_()` is implemented to
allow for this syntax:
  {{{
  sage: A = macaulay2('matrix {{1,2},{3,4}}')
  sage: matrix(QQ, A)
  [1 2]
  [3 4]
  }}}
  This ticket also fixes an issue where the elements are not promoted to
the correct ring:
  {{{
  sage: R.<x,y> = QQ[]
  sage: m = macaulay2(matrix(R, [[1, 2], [3, 4]]))
  sage: m.ring()  # should be R
  ZZ
  }}}

• finite fields: An issue is fixed where the generator names are not
preserved:
  {{{
  sage: K = GF(49, 'b')
  sage: K.gens(), macaulay2(K).gens()  # should be the same
  ((b,), {a})
  }}}

URL: https://trac.sagemath.org/28566
Reported by: gh-mwageringel
Ticket author(s): Markus Wageringel
Reviewer(s): Franco Saliola
  • Loading branch information
Release Manager committed Oct 10, 2019
2 parents 90948f4 + 21025bd commit 36c8eff
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 8 deletions.
33 changes: 30 additions & 3 deletions src/sage/interfaces/macaulay2.py
Expand Up @@ -1357,6 +1357,11 @@ def _sage_(self):
sage: R.sage() # optional - macaulay2
Vector space of dimension 2 over Rational Field
sage: macaulay2("vector {4_QQ, 2}").sage() # optional - macaulay2
(4, 2)
sage: _.parent() # optional - macaulay2
Vector space of dimension 2 over Rational Field
sage: m = macaulay2('"hello"') # optional - macaulay2
sage: m.sage() # optional - macaulay2
'hello'
Expand All @@ -1377,10 +1382,8 @@ def _sage_(self):
if cls_str == "List":
return [entry._sage_() for entry in self]
elif cls_str == "Matrix":
from sage.matrix.all import matrix
base_ring = self.ring()._sage_()
entries = self.entries()._sage_()
return matrix(base_ring, entries)
return self._matrix_(base_ring)
elif cls_str == 'HashTable':
return {x._sage_(): y._sage_() for (x, y) in self.pairs()}
elif cls_str == "Ideal":
Expand Down Expand Up @@ -1468,6 +1471,9 @@ def _sage_(self):
from sage.misc.sage_eval import sage_eval
gens_dict = parent.gens_dict()
return sage_eval(self.external_string(), gens_dict)
elif cls_cls_str == "Module":
entries = self.entries()._sage_()
return parent._element_constructor_(entries)

from sage.misc.sage_eval import sage_eval
try:
Expand All @@ -1478,6 +1484,27 @@ def _sage_(self):
from sage.misc.superseded import deprecated_function_alias
to_sage = deprecated_function_alias(27848, ExpectElement.sage)

def _matrix_(self, R):
r"""
If ``self`` is a Macaulay2 matrix, return the corresponding Sage matrix
over the Sage ring ``R``.
INPUT:
- ``R`` - ring to coerce into
OUTPUT: matrix
EXAMPLES::
sage: A = macaulay2('matrix {{1,2},{3,4}}') # optional - macaulay2
sage: matrix(QQ, A) # optional - macaulay2, indirect doctest
[1 2]
[3 4]
"""
from sage.matrix.all import matrix
return matrix(R, self.entries()._sage_())


@instancedoc
class Macaulay2Function(ExpectFunction):
Expand Down
17 changes: 14 additions & 3 deletions src/sage/matrix/matrix1.pyx
Expand Up @@ -440,10 +440,21 @@ cdef class Matrix(Matrix0):
sage: macaulay2(m) #optional - macaulay2
| x y |
| x+1 y+1 |
TESTS:
Entries of the matrix get promoted to the base ring (:trac:`28566`)::
sage: R.<x,y> = QQ[]
sage: m = macaulay2(matrix(R, [[1, 2], [3, 4]])) # optional - macaulay2
sage: m.ring()._operator('===', R).sage() # optional - macaulay2
True
"""
base_ring = macaulay2(self.base_ring())
entries = list(map(list, self))
return macaulay2(entries).matrix()
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
entries = [list(row) for row in self]
return macaulay2(self.base_ring()).matrix(entries)


def _scilab_init_(self):
Expand Down
35 changes: 35 additions & 0 deletions src/sage/modules/free_module_element.pyx
Expand Up @@ -3485,6 +3485,41 @@ cdef class FreeModuleElement(Vector): # abstract base class
"""
return True

def _macaulay2_(self, macaulay2=None):
r"""
Convert this vector to a Macaulay2 vector.
EXAMPLES::
sage: vector(QQ, [1, 2, 3])._macaulay2_() # optional - macaulay2
| 1 |
| 2 |
| 3 |
sage: _.ring() # optional - macaulay2
QQ
::
sage: R.<x,y> = QQ[]
sage: macaulay2(vector(R, [1, x+y])) # optional - macaulay2
| 1 |
| x+y |
TESTS:
Entries of the vector get promoted to the base ring::
sage: R.<x,y> = QQ[]
sage: v = macaulay2(vector(R, [1, 2])) # optional - macaulay2
sage: v.ring()._operator('===', R).sage() # optional - macaulay2
True
"""
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
return (macaulay2(self.base_ring()).matrix([self.list()]).transpose()
.vector())

def _mathematica_init_(self):
"""
Returns string representation of this vector as a Mathematica
Expand Down
15 changes: 13 additions & 2 deletions src/sage/rings/finite_rings/finite_field_base.pyx
Expand Up @@ -251,14 +251,25 @@ cdef class FiniteField(Field):
EXAMPLES::
sage: GF(97,'a')._macaulay2_init_()
'GF 97'
'GF(97,Variable=>symbol x)'
sage: macaulay2(GF(97, 'a')) # optional - macaulay2
GF 97
sage: macaulay2(GF(49, 'a')) # optional - macaulay2
GF 49
TESTS:
The variable name is preserved (:trac:`28566`)::
sage: K = macaulay2(GF(49, 'b')) # optional - macaulay2
sage: K.gens() # optional - macaulay2
{b}
sage: K._sage_() # optional - macaulay2
Finite Field in b of size 7^2
"""
return "GF %s"%(self.order())
return "GF(%s,Variable=>symbol %s)" % (self.order(),
self.variable_name())

def _sage_input_(self, sib, coerced):
r"""
Expand Down

0 comments on commit 36c8eff

Please sign in to comment.