Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit 70d1655

Browse files
author
Release Manager
committed
Trac #30402: Cannot load an object containing a matrix if it was saved from Python 2 Sage
I am currently trying to convert my Boolean-Cayley-graphs project from Python 2 to Python 3 Sage. https://github.com/penguian/Boolean-Cayley- graphs/tree/23-port-to-python-3 I have succeeded in converting the code, but cannot load objects that were saved by my previous Python 2-based code. These objects contain matrices as members. As far as I can tell, load(...,encoding='latin-1') fails to load a dict containing a matrix but load(...,encoding='bytes') loads but does not restore the original object. See the attachments, showing a script run on Cocalc, and its results. Along the way, we fix some code style etc. in `src/sage/matrix/matrix_integer_dense.pyx'.b Blocker for 9.2 because this defect is in the way of adoption of python3-based Sage versions by users. URL: https://trac.sagemath.org/30402 Reported by: gh-penguian Ticket author(s): Nils Bruin, John Palmieri, Jonathan Kliem Reviewer(s): Dima Pasechnik, Paul Leopardi
2 parents 3ac4f4a + c352b8a commit 70d1655

File tree

3 files changed

+115
-91
lines changed

3 files changed

+115
-91
lines changed

build/pkgs/configure/checksums.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
tarball=configure-VERSION.tar.gz
2-
sha1=9444dc8411d9182f3f4b188fcbfdd6f78039b551
3-
md5=454b419945489d4e3460e9858bb00c72
4-
cksum=982751597
2+
sha1=2a9b847a196754d70b3700f8a7d49c4679470200
3+
md5=2c161289c61683db84c35b25b30192d8
4+
cksum=3321925750
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
31306b77dc7696eb12c3fb1df0096c98a587bc93
1+
7c8149569bdf17c1508fc0d3786d7a4c74599cd0

src/sage/matrix/matrix_integer_dense.pyx

Lines changed: 111 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
377377

378378
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
379379
"""
380-
Returns (i, j) entry of self as a new Integer.
380+
Return (i, j) entry of self as a new Integer.
381381
382382
.. WARNING::
383383
@@ -431,7 +431,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
431431

432432
cdef inline double get_unsafe_double(self, Py_ssize_t i, Py_ssize_t j):
433433
"""
434-
Returns (j, i) entry of self as a new Integer.
434+
Return (j, i) entry of self as a new Integer.
435435
436436
.. WARNING::
437437
@@ -550,7 +550,23 @@ cdef class Matrix_integer_dense(Matrix_dense):
550550
return data
551551

552552
def _unpickle(self, data, int version):
553+
"""
554+
TESTS::
555+
556+
sage: b = matrix(ZZ,2,3, [0,0,0, 0, 0, 0])
557+
sage: s = b'1 61 f -2 3 0'
558+
sage: t = s.decode()
559+
sage: b._unpickle(s, 0) == b._unpickle(t, 0)
560+
True
561+
sage: b
562+
[ 1 193 15]
563+
[ -2 3 0]
564+
"""
553565
if version == 0:
566+
if isinstance(data, str):
567+
# old Py2 pickle: old "bytes" object reaches us as a
568+
# latin1-encoded string.
569+
data = data.encode('latin1')
554570
if isinstance(data, bytes):
555571
self._unpickle_version0(data)
556572
elif isinstance(data, list):
@@ -615,7 +631,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
615631

616632
def __copy__(self):
617633
r"""
618-
Returns a new copy of this matrix.
634+
Return a new copy of this matrix.
619635
620636
EXAMPLES::
621637
@@ -1029,13 +1045,13 @@ cdef class Matrix_integer_dense(Matrix_dense):
10291045
# TODO: Implement better
10301046
cdef _vector_times_matrix_(self, Vector v):
10311047
"""
1032-
Returns the vector times matrix product.
1048+
Return the vector times matrix product.
10331049
10341050
INPUT:
10351051
10361052
- ``v`` - a free module element.
10371053
1038-
OUTPUT: The vector times matrix product v\*A.
1054+
OUTPUT: The vector times matrix product ``v*A``.
10391055
10401056
EXAMPLES::
10411057
@@ -1688,63 +1704,63 @@ cdef class Matrix_integer_dense(Matrix_dense):
16881704

16891705
def symplectic_form(self):
16901706
r"""
1691-
Find a symplectic basis for self if self is an anti-symmetric,
1692-
alternating matrix.
1693-
1694-
Returns a pair (F, C) such that the rows of C form a symplectic
1695-
basis for self and F = C \* self \* C.transpose().
1696-
1697-
Raises a ValueError if self is not anti-symmetric, or self is not
1698-
alternating.
1699-
1700-
Anti-symmetric means that `M = -M^t`. Alternating means
1701-
that the diagonal of `M` is identically zero.
1702-
1703-
A symplectic basis is a basis of the form
1704-
`e_1, \ldots, e_j, f_1, \ldots f_j, z_1, \dots, z_k`
1705-
such that
1706-
1707-
- `z_i M v^t` = 0 for all vectors `v`
1708-
1709-
- `e_i M {e_j}^t = 0` for all `i, j`
1710-
1711-
- `f_i M {f_j}^t = 0` for all `i, j`
1712-
1713-
- `e_i M {f_i}^t = 1` for all `i`
1714-
1715-
- `e_i M {f_j}^t = 0` for all `i` not equal
1716-
`j`.
1717-
1718-
The ordering for the factors `d_{i} | d_{i+1}` and for
1719-
the placement of zeroes was chosen to agree with the output of
1720-
:meth:`smith_form`.
1721-
1722-
See the example for a pictorial description of such a basis.
1723-
1724-
EXAMPLES::
1725-
1726-
sage: E = matrix(ZZ, 5, 5, [0, 14, 0, -8, -2, -14, 0, -3, -11, 4, 0, 3, 0, 0, 0, 8, 11, 0, 0, 8, 2, -4, 0, -8, 0]); E
1727-
[ 0 14 0 -8 -2]
1728-
[-14 0 -3 -11 4]
1729-
[ 0 3 0 0 0]
1730-
[ 8 11 0 0 8]
1731-
[ 2 -4 0 -8 0]
1732-
sage: F, C = E.symplectic_form()
1733-
sage: F
1734-
[ 0 0 1 0 0]
1735-
[ 0 0 0 2 0]
1736-
[-1 0 0 0 0]
1737-
[ 0 -2 0 0 0]
1738-
[ 0 0 0 0 0]
1739-
sage: F == C * E * C.transpose()
1740-
True
1741-
sage: E.smith_form()[0]
1742-
[1 0 0 0 0]
1743-
[0 1 0 0 0]
1744-
[0 0 2 0 0]
1745-
[0 0 0 2 0]
1746-
[0 0 0 0 0]
1747-
"""
1707+
Find a symplectic basis for self if self is an anti-symmetric,
1708+
alternating matrix.
1709+
1710+
Return a pair (F, C) such that the rows of C form a symplectic
1711+
basis for self and ``F = C * self * C.transpose()``.
1712+
1713+
Raise a ValueError if self is not anti-symmetric, or self is not
1714+
alternating.
1715+
1716+
Anti-symmetric means that `M = -M^t`. Alternating means
1717+
that the diagonal of `M` is identically zero.
1718+
1719+
A symplectic basis is a basis of the form
1720+
`e_1, \ldots, e_j, f_1, \ldots f_j, z_1, \dots, z_k`
1721+
such that
1722+
1723+
- `z_i M v^t` = 0 for all vectors `v`
1724+
1725+
- `e_i M {e_j}^t = 0` for all `i, j`
1726+
1727+
- `f_i M {f_j}^t = 0` for all `i, j`
1728+
1729+
- `e_i M {f_i}^t = 1` for all `i`
1730+
1731+
- `e_i M {f_j}^t = 0` for all `i` not equal
1732+
`j`.
1733+
1734+
The ordering for the factors `d_{i} | d_{i+1}` and for
1735+
the placement of zeroes was chosen to agree with the output of
1736+
:meth:`smith_form`.
1737+
1738+
See the example for a pictorial description of such a basis.
1739+
1740+
EXAMPLES::
1741+
1742+
sage: E = matrix(ZZ, 5, 5, [0, 14, 0, -8, -2, -14, 0, -3, -11, 4, 0, 3, 0, 0, 0, 8, 11, 0, 0, 8, 2, -4, 0, -8, 0]); E
1743+
[ 0 14 0 -8 -2]
1744+
[-14 0 -3 -11 4]
1745+
[ 0 3 0 0 0]
1746+
[ 8 11 0 0 8]
1747+
[ 2 -4 0 -8 0]
1748+
sage: F, C = E.symplectic_form()
1749+
sage: F
1750+
[ 0 0 1 0 0]
1751+
[ 0 0 0 2 0]
1752+
[-1 0 0 0 0]
1753+
[ 0 -2 0 0 0]
1754+
[ 0 0 0 0 0]
1755+
sage: F == C * E * C.transpose()
1756+
True
1757+
sage: E.smith_form()[0]
1758+
[1 0 0 0 0]
1759+
[0 1 0 0 0]
1760+
[0 0 2 0 0]
1761+
[0 0 0 2 0]
1762+
[0 0 0 0 0]
1763+
"""
17481764
import sage.matrix.symplectic_basis
17491765
return sage.matrix.symplectic_basis.symplectic_basis_over_ZZ(self)
17501766

@@ -1987,18 +2003,22 @@ cdef class Matrix_integer_dense(Matrix_dense):
19872003
"""
19882004
key = 'hnf-%s-%s'%(include_zero_rows,transformation)
19892005
ans = self.fetch(key)
1990-
if ans is not None: return ans
2006+
if ans is not None:
2007+
return ans
19912008

19922009
cdef Matrix_integer_dense H_m,w,U
19932010
cdef Py_ssize_t nr, nc, n, i, j
19942011
nr = self._nrows
19952012
nc = self._ncols
19962013
n = nr if nr >= nc else nc
19972014
if algorithm == 'default':
1998-
if transformation: algorithm = 'flint'
2015+
if transformation:
2016+
algorithm = 'flint'
19992017
else:
2000-
if n < 75: algorithm = 'pari0'
2001-
else: algorithm = 'flint'
2018+
if n < 75:
2019+
algorithm = 'pari0'
2020+
else:
2021+
algorithm = 'flint'
20022022
proof = get_proof_flag(proof, "linear_algebra")
20032023
pivots = None
20042024

@@ -2236,7 +2256,8 @@ cdef class Matrix_integer_dense(Matrix_dense):
22362256
[ 0 0 0]
22372257
"""
22382258
p = self.fetch('pivots')
2239-
if not p is None: return tuple(p)
2259+
if not p is None:
2260+
return tuple(p)
22402261

22412262
cdef Matrix_integer_dense E
22422263
E = self.echelon_form()
@@ -2430,8 +2451,10 @@ cdef class Matrix_integer_dense(Matrix_dense):
24302451
if not transformation:
24312452
return D
24322453

2433-
if self._ncols == 0: v[0] = self.matrix_space(ncols = self._nrows)(1)
2434-
if self._nrows == 0: v[1] = self.matrix_space(nrows = self._ncols)(1)
2454+
if self._ncols == 0:
2455+
v[0] = self.matrix_space(ncols = self._nrows)(1)
2456+
if self._nrows == 0:
2457+
v[1] = self.matrix_space(nrows = self._ncols)(1)
24352458

24362459
if self._ncols == 0:
24372460
# silly special cases for matrices with 0 columns (PARI has a unique empty matrix)
@@ -2524,7 +2547,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
25242547

25252548
def _right_kernel_matrix(self, **kwds):
25262549
r"""
2527-
Returns a pair that includes a matrix of basis vectors
2550+
Return a pair that includes a matrix of basis vectors
25282551
for the right kernel of ``self``.
25292552
25302553
INPUT:
@@ -2542,7 +2565,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
25422565
25432566
OUTPUT:
25442567
2545-
Returns a pair. First item is the string is either
2568+
Return a pair. First item is the string is either
25462569
'computed-flint-int', 'computed-pari-int', 'computed-flint-int', which identifies
25472570
the nature of the basis vectors.
25482571
@@ -2685,7 +2708,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
26852708
EXAMPLES::
26862709
26872710
sage: m = matrix(ZZ,3,[1..9])
2688-
sage: m.adjugate()
2711+
sage: m.adjugate() # indirect doctest
26892712
[ -3 6 -3]
26902713
[ 6 -12 6]
26912714
[ -3 6 -3]
@@ -3578,7 +3601,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
35783601
35793602
35803603
ALGORITHM: The p-adic algorithm works by first finding a random
3581-
vector v, then solving A\*x = v and taking the denominator
3604+
vector v, then solving `Ax = v` and taking the denominator
35823605
`d`. This gives a divisor of the determinant. Then we
35833606
compute `\det(A)/d` using a multimodular algorithm and the
35843607
Hadamard bound, skipping primes that divide `d`.
@@ -3889,7 +3912,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
38893912
check that the matrix is invertible.
38903913
38913914
3892-
OUTPUT: A, d such that A\*self = d
3915+
OUTPUT: A, d such that ``A*self == d``
38933916
38943917
38953918
- ``A`` - a matrix over ZZ
@@ -3945,7 +3968,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
39453968
39463969
- ``self`` - an invertible matrix
39473970
3948-
OUTPUT: A, d such that A\*self = d
3971+
OUTPUT: A, d such that ``A*self == d``
39493972
39503973
39513974
- ``A`` - a matrix over ZZ
@@ -4226,8 +4249,8 @@ cdef class Matrix_integer_dense(Matrix_dense):
42264249
def _solve_iml(self, Matrix_integer_dense B, right=True):
42274250
"""
42284251
Let A equal self be a square matrix. Given B return an integer
4229-
matrix C and an integer d such that self C\*A == d\*B if right is
4230-
False or A\*C == d\*B if right is True.
4252+
matrix C and an integer d such that self ``C*A == d*B`` if right is
4253+
False or ``A*C == d*B`` if right is True.
42314254
42324255
OUTPUT:
42334256
@@ -4392,8 +4415,8 @@ cdef class Matrix_integer_dense(Matrix_dense):
43924415
def _solve_flint(self, Matrix_integer_dense B, right=True):
43934416
"""
43944417
Let A equal self be a square matrix. Given B return an integer
4395-
matrix C and an integer d such that self C\*A == d\*B if right is
4396-
False or A\*C == d\*B if right is True.
4418+
matrix C and an integer d such that self ``C*A == d*B`` if right is
4419+
False or ``A*C == d*B`` if right is True.
43974420
43984421
OUTPUT:
43994422
@@ -4548,7 +4571,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
45484571
45494572
45504573
If you put standard basis vectors in order at the pivot columns,
4551-
and put the matrix (1/d)\*X everywhere else, then you get the
4574+
and put the matrix ``(1/d)*X`` everywhere else, then you get the
45524575
reduced row echelon form of self, without zero rows at the bottom.
45534576
45544577
.. NOTE::
@@ -4708,7 +4731,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
47084731

47094732
def decomposition(self, **kwds):
47104733
"""
4711-
Returns the decomposition of the free module on which this matrix A
4734+
Return the decomposition of the free module on which this matrix A
47124735
acts from the right (i.e., the action is x goes to x A), along with
47134736
whether this matrix acts irreducibly on each factor. The factors
47144737
are guaranteed to be sorted in the same way as the corresponding
@@ -4879,7 +4902,8 @@ cdef class Matrix_integer_dense(Matrix_dense):
48794902
row_i = A.row(i)
48804903
row_n = A.row(n)
48814904

4882-
ag = a//g; bg = b//g
4905+
ag = a//g
4906+
bg = b//g
48834907

48844908
new_top = s*row_i + t*row_n
48854909
new_bot = bg*row_i - ag*row_n
@@ -4937,7 +4961,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
49374961
INPUT:
49384962
49394963
- ``D`` -- a small integer that is assumed to be a
4940-
multiple of 2\*det(self)
4964+
multiple of ``2*det(self)``
49414965
49424966
OUTPUT:
49434967
@@ -5071,7 +5095,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
50715095
R = R/d
50725096
i += 1
50735097
j = i
5074-
if i == nrows :
5098+
if i == nrows:
50755099
break # return res
50765100
if T_rows[i][i] == 0:
50775101
T_rows[i][i] = R
@@ -5163,7 +5187,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
51635187

51645188
def augment(self, right, subdivide=False):
51655189
r"""
5166-
Returns a new matrix formed by appending the matrix
5190+
Return a new matrix formed by appending the matrix
51675191
(or vector) ``right`` on the right side of ``self``.
51685192
51695193
INPUT:
@@ -5484,7 +5508,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
54845508

54855509
def transpose(self):
54865510
"""
5487-
Returns the transpose of self, without changing self.
5511+
Return the transpose of self, without changing self.
54885512
54895513
EXAMPLES:
54905514
@@ -5535,7 +5559,7 @@ cdef class Matrix_integer_dense(Matrix_dense):
55355559

55365560
def antitranspose(self):
55375561
"""
5538-
Returns the antitranspose of self, without changing self.
5562+
Return the antitranspose of self, without changing self.
55395563
55405564
EXAMPLES::
55415565

0 commit comments

Comments
 (0)