Skip to content

Commit

Permalink
Trac #28591: convert chain complexes from Macaulay2 to Sage
Browse files Browse the repository at this point in the history
This ticket implements conversion of chain complexes from Macaulay2 to
Sage, for example:
{{{
            sage: R = ZZ['a,b,c']
            sage: C = macaulay2(ideal(R.gens())).resolution()
            sage: unicode_art(C.sage())
                                   ⎛-b  0 -c⎞     ⎛ c⎞
                                   ⎜ a -c  0⎟     ⎜ a⎟
                       (a b c)     ⎝ 0  b  a⎠     ⎝-b⎠
             0 ⟵── C_0 ⟵────── C_1 ⟵───────── C_2 ⟵─── C_3 ⟵── 0
}}}

This ticket also fixes an issue where matrices of size 0×n failed to
convert correctly.

URL: https://trac.sagemath.org/28591
Reported by: gh-mwageringel
Ticket author(s): Markus Wageringel
Reviewer(s): Frédéric Chapoton, Dima Pasechnik
  • Loading branch information
Release Manager committed Oct 28, 2019
2 parents d2838a5 + adb0a1a commit 9e0e0fd
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 3 deletions.
66 changes: 63 additions & 3 deletions src/sage/interfaces/macaulay2.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,8 @@ def help(self, s):
"""
EXAMPLES::
sage: macaulay2.help("load") # optional - macaulay2 - 1st call might be chatty...
...
sage: macaulay2.help("load") # optional - macaulay2
load...
****...
Expand Down Expand Up @@ -1293,7 +1295,7 @@ def underscore(self, x):
#Conversion to Sage#
####################
def _sage_(self):
"""
r"""
EXAMPLES::
sage: macaulay2(ZZ).sage() # optional - macaulay2, indirect doctest
Expand Down Expand Up @@ -1366,7 +1368,7 @@ def _sage_(self):
sage: m.sage() # optional - macaulay2
'hello'
sage: macaulay2.needsPackage('"Graphs"'); # optional - macaulay2
sage: gg = macaulay2.needsPackage('"Graphs"') # optional - macaulay2
sage: g = macaulay2.barbellGraph(3) # optional - macaulay2
sage: g.sage() # optional - macaulay2
Graph on 6 vertices
Expand All @@ -1380,6 +1382,27 @@ def _sage_(self):
sage: g.sage().edges(labels=False) # optional - macaulay2
[(1, 2), (2, 1), (3, 1)]
Chain complexes and maps of chain complexes can be converted::
sage: R = ZZ['a,b,c']
sage: C = macaulay2(ideal(R.gens())).resolution() # optional - macaulay2
sage: ascii_art(C.sage()) # optional - macaulay2
[-b 0 -c] [ c]
[ a -c 0] [ a]
[a b c] [ 0 b a] [-b]
0 <-- C_0 <-------- C_1 <----------- C_2 <----- C_3 <-- 0
sage: F = C.dot('dd') # optional - macaulay2
sage: G = F.sage() # optional - macaulay2
sage: G.in_degree(2) # optional - macaulay2
[-b 0 -c]
[ a -c 0]
[ 0 b a]
sage: F.underscore(2).sage() == G.in_degree(2) # optional - macaulay2
True
sage: (F^2).sage() # optional - macaulay2
Chain complex morphism:
From: Chain complex with at most 4 nonzero terms over Multivariate Polynomial Ring in a, b, c over Integer Ring
To: Chain complex with at most 4 nonzero terms over Multivariate Polynomial Ring in a, b, c over Integer Ring
"""
repr_str = str(self)
cls_str = str(self.cls())
Expand Down Expand Up @@ -1477,6 +1500,30 @@ def _sage_(self):
g = graph_cls(adj_mat, format='adjacency_matrix')
g.relabel(self.vertices())
return g
elif cls_str == "ChainComplex":
from sage.homology.chain_complex import ChainComplex
ring = self.ring()._sage_()
dd = self.dot('dd')
degree = dd.degree()._sage_()
a = self.min()._sage_()
b = self.max()._sage_()
matrices = {i: dd.underscore(i)._matrix_(ring)
for i in range(a, b+1)}
return ChainComplex(matrices, degree=degree)
elif cls_str == "ChainComplexMap":
from sage.homology.chain_complex_morphism import ChainComplexMorphism
ring = self.ring()._sage_()
source = self.source()
a = source.min()._sage_()
b = source.max()._sage_()
degree = self.degree()._sage_()
matrices = {i: self.underscore(i)._matrix_(ring)
for i in range(a, b+1)}
C = source._sage_()
# in Sage, chain complex morphisms are degree-preserving,
# so we shift the degrees of the target
D = self.target()._operator(' ', '[%s]' % degree)._sage_()
return ChainComplexMorphism(matrices, C, D)
else:
#Handle the integers and rationals separately
if cls_str == "ZZ":
Expand Down Expand Up @@ -1526,9 +1573,22 @@ def _matrix_(self, R):
sage: matrix(QQ, A) # optional - macaulay2, indirect doctest
[1 2]
[3 4]
TESTS:
Check that degenerate matrix dimensions are preserved (:trac:`28591`)::
sage: m = macaulay2('matrix {{},{}}') # optional - macaulay2
sage: matrix(ZZ, m).dimensions() # optional - macaulay2
(2, 0)
sage: matrix(ZZ, m.transpose()).dimensions() # optional - macaulay2
(0, 2)
"""
from sage.matrix.all import matrix
return matrix(R, self.entries()._sage_())
m = matrix(R, self.entries()._sage_())
if not m.nrows():
return matrix(R, 0, self.numcols()._sage_())
return m


@instancedoc
Expand Down
11 changes: 11 additions & 0 deletions src/sage/matrix/matrix1.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,21 @@ cdef class Matrix(Matrix0):
sage: m = macaulay2(matrix(R, [[1, 2], [3, 4]])) # optional - macaulay2
sage: m.ring()._operator('===', R).sage() # optional - macaulay2
True
Check that degenerate matrix dimensions are handled correctly
(:trac:`28591`)::
sage: macaulay2(matrix(QQ, 2, 0)).numrows() # optional - macaulay2
2
sage: macaulay2(matrix(QQ, 0, 2)).numcols() # optional - macaulay2
2
"""
if macaulay2 is None:
from sage.interfaces.macaulay2 import macaulay2 as m2_default
macaulay2 = m2_default
if not self.nrows():
return (macaulay2(self.base_ring())
.matrix('toList(%s:{})' % self.ncols()).transpose())
entries = [list(row) for row in self]
return macaulay2(self.base_ring()).matrix(entries)

Expand Down

0 comments on commit 9e0e0fd

Please sign in to comment.