Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# cython: profile=True """ Lean matrices
Internal data structures for the ``LinearMatroid`` class and some subclasses. Note that many of the methods are ``cdef``, and therefore only available from Cython code.
.. warning::
Intended for internal use by the ``LinearMatroid`` classes only. End users should work with Sage matrices instead. Methods that are used outside lean_matrix.pyx and have no equivalent in Sage's ``Matrix`` have been flagged in the code, as well as where they are used, by ``# Not a Sage matrix operation`` or ``# Deprecated Sage matrix operation``.
AUTHORS:
- Rudi Pendavingh, Stefan van Zwam (2013-04-01): initial version
""" #***************************************************************************** # Copyright (C) 2013 Rudi Pendavingh <rudi.pendavingh@gmail.com> # Copyright (C) 2013 Stefan van Zwam <stefanvanzwam@gmail.com> # # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
include 'sage/data_structures/bitset.pxi' from libc.string cimport memcpy, memset from cpython.object cimport Py_EQ, Py_NE from cysignals.memory cimport sig_malloc, sig_realloc, sig_free
from sage.matrix.matrix2 cimport Matrix from sage.rings.integer cimport Integer
cdef class LeanMatrix: """ Lean matrices
Sage's matrix classes are powerful, versatile, and often very fast. However, their performance with regard to pivoting (pretty much the only task performed on them within the context of matroids) leaves something to be desired. The LeanMatrix classes provide the LinearMatroid classes with a custom, light-weight data structure to store and manipulate matrices.
This is the abstract base class. Most methods are not implemented; this is only to fix the interface.
.. NOTE::
This class is intended for internal use by the LinearMatroid class only. Hence it does not derive from ``SageObject``. If ``A`` is a LeanMatrix instance, and you need access from other parts of Sage, use ``Matrix(A)`` instead.
EXAMPLES::
sage: M = Matroid(ring=GF(5), matrix=[[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]]) # indirect doctest sage: M.is_isomorphic(matroids.Uniform(2, 5)) True """ def __init__(self, long m, long n, M=None): """ Initialize a lean matrix; see class documentation for more info.
EXAMPLES::
sage: from sage.matroids.lean_matrix import LeanMatrix sage: A = LeanMatrix(3, 4) sage: A.ncols() 4 """
def __repr__(self): """ Return a string representation.
EXAMPLES::
sage: from sage.matroids.lean_matrix import LeanMatrix sage: A = LeanMatrix(3, 4) sage: repr(A) 'LeanMatrix instance with 3 rows and 4 columns' """
def _matrix_(self): """ Return a matrix version.
EXAMPLES::
sage: from sage.matroids.lean_matrix import GenericMatrix sage: A = Matrix(GF(5), [[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]]) sage: A == GenericMatrix(2, 5, A)._matrix_() True """ cdef long r, c
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation """ Make a copy of ``self``. """ cdef LeanMatrix A = type(self)(self.nrows(), self.ncols(), self) return A
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows of ``self`` to ``k``. Preserves data. """ raise NotImplementedError
cdef LeanMatrix stack(self, LeanMatrix M): """ Stack ``self`` on top of ``M``. Assumes ``self`` and ``M`` are of same type, and compatible dimensions. """ cdef LeanMatrix A cdef long i, j cdef long sr = self.nrows() A = type(self)(sr + M.nrows(), self.ncols()) for i from 0 <= i < sr: for j from 0 <= j < self.ncols(): A.set_unsafe(i, j, self.get_unsafe(i, j)) for i from 0 <= i < M.nrows(): for j from 0 <= j < M.ncols(): A.set_unsafe(i + sr, j, M.get_unsafe(i, j)) return A
cdef LeanMatrix augment(self, LeanMatrix M): """ Concatenates ``self`` with ``M``, placing ``M`` to the right of ``self``. Assumes ``self`` and ``M`` are of same type, and compatible dimensions. """ cdef LeanMatrix A cdef long i, j cdef long sc = self.ncols() A = type(self)(self.nrows(), sc + M.ncols()) for i from 0 <= i < self.nrows(): for j from 0 <= j < sc: A.set_unsafe(i, j, self.get_unsafe(i, j)) for j from 0 <= j < M.ncols(): A.set_unsafe(i, j + sc, M.get_unsafe(i, j)) return A
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation """ Return the matrix obtained by prepending an identity matrix. Special case of ``augment``. """ cdef long i, j cdef LeanMatrix A = type(self)(self.nrows(), self.ncols() + self.nrows()) for i from 0 <= i < self.nrows(): A.set_unsafe(i, i, self.base_ring()(1)) for j from 0 <= j < self.ncols(): A.set_unsafe(i, self.nrows() + j, self.get_unsafe(i, j)) return A
cpdef long ncols(self) except -1: """ Return the number of columns.
EXAMPLES::
sage: from sage.matroids.lean_matrix import LeanMatrix sage: A = LeanMatrix(3, 4) sage: A.ncols() 4 """
cpdef long nrows(self) except -1: """ Return the number of rows.
EXAMPLES::
sage: from sage.matroids.lean_matrix import LeanMatrix sage: A = LeanMatrix(3, 4) sage: A.nrows() 3 """
cpdef base_ring(self): """ Return the base ring.
EXAMPLES::
sage: from sage.matroids.lean_matrix import LeanMatrix sage: A = LeanMatrix(3, 4) sage: A.base_ring() Traceback (most recent call last): ... NotImplementedError: subclasses need to implement this. """
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import GenericMatrix sage: A = GenericMatrix(3, 4, ring=GF(5)) sage: A.characteristic() 5 """ return self.base_ring().characteristic()
cdef get_unsafe(self, long r, long c): """ Return the value in row ``r``, column ``c``. """ raise NotImplementedError
cdef int set_unsafe(self, long r, long c, x) except -1: """ Set the value in row ``r``, column ``c`` to ``x``. """ raise NotImplementedError
cdef bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation """ Check if value in row ``r``, column ``c`` equals ``0``. """
cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1: """ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is ignored. """ cdef long i for i from 0 <= i < self._ncols: self.set_unsafe(x, i, self.get_unsafe(x, i) + self.get_unsafe(y, i)) else:
cdef int swap_rows_c(self, long x, long y) except -1: """ Swap rows ``x`` and ``y``. """ cdef long i for i from 0 <= i < self._ncols: tmp = self.get_unsafe(x, i) self.set_unsafe(x, i, self.get_unsafe(y, i)) self.set_unsafe(y, i, tmp) return 0
cdef int rescale_row_c(self, long x, s, bint col_start) except -1: """ Scale row ``x`` by ``s``. Argument ``col_start`` is for Sage compatibility, and is ignored. """ cdef long i
cdef int rescale_column_c(self, long y, s, bint start_row) except -1: """ Scale column ``y`` by ``s``. Argument ``start_row`` is for Sage compatibility, and ignored. """ cdef long j for j from 0 <= j < self._nrows: self.set_unsafe(j, y, self.get_unsafe(j, y) * s) return 0
cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation """ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes elsewhere.
Assumption (not checked): the entry in row ``x``, column ``y`` is nonzero to start with.
.. NOTE::
This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ cdef long i, j
cdef list gauss_jordan_reduce(self, columns): # Not a Sage matrix operation """ Row-reduce so the lexicographically first basis indexes an identity submatrix. """ cdef long c, p, row cdef bint is_pivot
cdef list nonzero_positions_in_row(self, long r): """ Get coordinates of nonzero entries of row ``r``. """ return [i for i in xrange(self._ncols) if self.is_nonzero(r, i)]
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef LeanMatrix A = type(self)(self.ncols(), self.nrows()) cdef long i, j for i from 0 <= i < self.nrows(): for j from 0 <= j < self.ncols(): A.set_unsafe(j, i, self.get_unsafe(i, j)) return A
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Multiply two matrices. Assumes ``self`` and ``M`` are of same type, and compatible dimensions. """ cdef LeanMatrix A = type(self)(self.nrows(), other.ncols()) cdef i, j, k for i from 0 <= i < self.nrows(): for j from 0 <= j < other.ncols(): for k from 0 <= k < self.ncols(): A.set_unsafe(i, j, self.get_unsafe(i, k) * other.get_unsafe(k, j)) return A
cdef LeanMatrix matrix_from_rows_and_columns(self, rows, columns): """ Return submatrix indexed by indicated rows and columns. """ cdef long r, c
def __mul__(left, right): """ Multiply two matrices, or multiply a matrix with a constant from the base ring.
Only works if both matrices are of the same type, or if the constant is the first operand and can be coerced into the base ring.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [1, 1]])) sage: B = GenericMatrix(3, 2, Matrix(GF(2), [[1, 0], [1, 0], [1, 0]])) sage: B * A LeanMatrix instance with 3 rows and 2 columns over Finite Field of size 2 """ cdef long i cdef LeanMatrix A else: return NotImplemented if not left in (<LeanMatrix>right).base_ring(): try: left = (<LeanMatrix>right).base_ring()(left) except (TypeError, NotImplemented, ValueError): return NotImplemented A = (<LeanMatrix>right).copy() for i from 0 <= i < A.nrows(): A.rescale_row_c(i, left, 0) return A
def __neg__(self): """ Return a matrix ``B`` such that ``self + B`` is the all-zero matrix.
Note that the `` + `` operator is currently not supported.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]])) sage: C = -A sage: -C == A True """ cdef long i
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: B = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: C = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: D = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: E = GenericMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j if op not in [Py_EQ, Py_NE]: return NotImplemented if not isinstance(left, LeanMatrix) or not isinstance(right, LeanMatrix): return NotImplemented if type(left) != type(right): return NotImplemented if op == Py_EQ: res = True if op == Py_NE: res = False # res gets inverted if matroids are deemed different. if left.nrows() != right.nrows(): return not res if left.ncols() != right.ncols(): return not res for i from 0 <= i < left.nrows(): for j from 0 <= j < left.ncols(): if (<LeanMatrix>left).get_unsafe(i, j) != (<LeanMatrix>right).get_unsafe(i, j): return not res return res
# In Cythonized classes, use ``__richcmp__()`` instead of ``__eq__()``, ``__ne__()``.
# Copying, loading, saving:
def __copy__(self): """ Return a copy of ``self``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 5, Matrix(GF(5), [[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]])) sage: A == copy(A) # indirect doctest True """
""" Return a deep copy of ``self``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 5, Matrix(GF(5), [[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]])) sage: A == deepcopy(A) # indirect doctest True """
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = LeanMatrix(2, 5) sage: A == loads(dumps(A)) # indirect doctest Traceback (most recent call last): ... NotImplementedError: subclasses need to implement this. """
cdef shifting_all(self, P_rows, P_cols, Q_rows, Q_cols, int m): r""" Given a partial matrix `M`. If the submatrix `M` using rows `P_rows` columns `P_cols` and submatrix using rows `Q_rows` columns `Q_cols` can be extended to a ``m``-separator, then it returns `True, E`, where `E` is a ``m``-separator. Otherwise it returns `False, None`
`P_rows` and `Q_rows` must be disjoint subsets of row indices. `P_cols` and `Q_cols` must be disjoint subsets of column indices.
Internal version does not verify the above properties hold.
INPUT:
- ``P_rows`` -- list of row indices of the first submatrix - ``P_cols`` -- list of column indices of the first submatrix - ``Q_rows`` -- list of row indices of the second submatrix - ``Q_cols`` -- list of column indices of the second submatrix - ``m`` -- separation size
OUTPUT:
- `False, None` -- if the input submatrices does not induce a `m``-separator. - `True, E` -- if there exist a ``m``-separator ``E``.
""" return True, cert return True, cert return True, cert
cdef shifting(self, U_1, V_2, U_2, V_1, z2, z1, int m): r""" Let `E_1` be the submatrix using rows `U_1` and columns `V_2` with optional column `z2` attached. Let `E_2` be the submatrix using rows `U_2` and columns `V_1` with optional column `z1` attached. If `E_1` and `E_2` can be extended to a ``m``-separator, then it returns `True, E`, where `E` is a ``m``-separator. Otherwise it returns `False, None`
`U_1` and `U_2` must be disjoint subsets of row indices. `V_1` and `V_2` must be disjoint subsets of column indices.
Internal version does not verify the above properties hold.
INPUT:
- ``U_1`` -- list of row indices of the first submatrix - ``V_2`` -- list of column indices of the first submatrix - ``U_2`` -- list of row indices of the second submatrix - ``V_1`` -- list of column indices of the second submatrix - ``z2`` -- start by add an additional column with index `z2` to `V_2` - ``z1`` -- start by add an additional column with index `z1` to `V_1` - ``m`` -- separation size
OUTPUT:
- `False, None` -- if the input submatrices does not induce a `m``-separator. - `True, (X,Y)` -- row indices `X` and column indices `Y` defines a ``m``-separator. """ # make copy because of destructive updates else:
# find a unique representation of every column in U_1xY_3 using columns in U_1xV_2 # find a unique representation of every rows in X_3xV_1 using rows in U_2xV_1
#rowshifts #colshifts
# size of S_2 return False, None
cdef class GenericMatrix(LeanMatrix): """ Matrix over arbitrary Sage ring.
INPUT:
- ``nrows`` -- number of rows - ``ncols`` -- number of columns - ``M`` -- (default: ``None``) a ``Matrix`` or ``GenericMatrix`` of dimensions at most ``m*n``. - ``ring`` -- (default: ``None``) a Sage ring.
.. NOTE::
This class is intended for internal use by the LinearMatroid class only. Hence it does not derive from ``SageObject``. If ``A`` is a LeanMatrix instance, and you need access from other parts of Sage, use ``Matrix(A)`` instead.
If the constructor is fed a GenericMatrix instance, the ``ring`` argument is ignored. Otherwise, the matrix entries will be converted to the appropriate ring.
EXAMPLES::
sage: M = Matroid(ring=GF(5), matrix=[[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]]) # indirect doctest sage: M.is_isomorphic(matroids.Uniform(2, 5)) True """
def __init__(self, long nrows, long ncols, M=None, ring=None): """ See class docstring for full information.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]])) # indirect doctest sage: B = GenericMatrix(2, 2, ring=GF(3)) sage: A == B True """ cdef long i, j # Overrides M's ring # Default: else: if ring_override: for i from 0 <= i < M.nrows(): for j from 0 <= j < M.ncols(): self._entries[i * self._ncols + j] = self._base_ring((<LeanMatrix>M).get_unsafe(i, j)) else: for i from 0 <= i < M.nrows(): for j from 0 <= j < M.ncols(): self._entries[i * self._ncols + j] = (<LeanMatrix>M).get_unsafe(i, j) else: # Sage Matrix or otherwise else:
def __repr__(self): """ Return representation.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]])) sage: repr(A) # indirect doctest 'LeanMatrix instance with 2 rows and 2 columns over Finite Field of size 3' """
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows to ``k``. Preserves data. """ cdef long l = len(self._entries) - k * self._ncols if l > 0: self._entries.extend([self._zero] * l) elif l < 0: del self._entries[k * self._ncols:] self._nrows = k return 0
cdef LeanMatrix stack(self, LeanMatrix M): """ Warning: assumes ``M`` is a GenericMatrix instance! """ cdef GenericMatrix A cdef long i, j A = GenericMatrix(0, 0, ring=self._base_ring) A._entries = self._entries + ((<GenericMatrix>M)._entries) A._nrows = self._nrows + M.nrows() A._ncols = self._ncols return A
cdef LeanMatrix augment(self, LeanMatrix M): """ Warning: assumes ``M`` is a GenericMatrix instance! """ cdef GenericMatrix A cdef long i cdef long Mn = M.ncols() A = GenericMatrix(self._nrows, self._ncols + Mn, ring=self._base_ring) for i from 0 <= i < self._nrows: A._entries[i * A._ncols:i * A._ncols + self._ncols] = self._entries[i * self._ncols:(i + 1) * self._ncols] A._entries[i * A._ncols + self._ncols:(i + 1) * A._ncols]=(<GenericMatrix>M)._entries[i * Mn:(i + 1) * Mn] return A
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation cdef GenericMatrix A = GenericMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring) for i from 0 <= i < self._nrows: A._entries[i * A._ncols + i] = self._one A._entries[i * A._ncols + self._nrows:(i + 1) * A._ncols]=self._entries[i * self._ncols:(i + 1) * self._ncols] return A
cpdef base_ring(self): """ Return the base ring of ``self``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import GenericMatrix sage: A = GenericMatrix(3, 4, ring=GF(5)) sage: A.base_ring() Finite Field of size 5 """
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import GenericMatrix sage: A = GenericMatrix(3, 4, ring=GF(5)) sage: A.characteristic() 5 """
cdef get_unsafe(self, long r, long c):
cdef int set_unsafe(self, long r, long c, x) except -1:
cdef int swap_rows_c(self, long x, long y) except -1: """ Swap rows ``x`` and ``y``. """
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef GenericMatrix A cdef long i, j
cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation """ Return the inner product between rows ``i`` and ``j``. """ cdef long k res = 0 for k from 0 <= k < self._ncols: x = self.get_unsafe(i, k) y = self.get_unsafe(j, k) if y and y != self._one: y += self._one res += x * y return res
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Return the product ``self * other``. """ cdef GenericMatrix A, ot cdef long i, j, t
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: B = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: C = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: D = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: E = GenericMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j return NotImplemented # res gets inverted if matroids are deemed different. return not res return not res
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(2, 5, ring=QQ) sage: A == loads(dumps(A)) # indirect doctest True sage: C = GenericMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]])) sage: C == loads(dumps(C)) True """
# Binary matrices
cdef GF2, GF2_one, GF2_zero
cdef class BinaryMatrix(LeanMatrix): """ Binary matrix class. Entries are stored bit-packed into integers.
INPUT:
- ``m`` -- Number of rows. - ``n`` -- Number of columns. - ``M`` -- (default: ``None``) Matrix or BinaryMatrix instance. Assumption: dimensions of ``M`` are at most ``m`` by ``n``. - ``ring`` -- (default: ``None``) ignored.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 2, Matrix(GF(7), [[0, 0], [0, 0]])) sage: B = BinaryMatrix(2, 2, ring=GF(5)) sage: C = BinaryMatrix(2, 2) sage: A == B and A == C True """ def __cinit__(self, long m, long n, object M=None, object ring=None): """ Init internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j else:
def __init__(self, long m, long n, object M=None, object ring=None): """ See class docstring for full specification.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j global GF2, GF2_zero, GF2_one, GF2_not_defined else: raise TypeError("unrecognized input type")
def __dealloc__(self): cdef long i
def __repr__(self): r""" Return representation string
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) sage: repr(A) # indirect doctest '2 x 3 BinaryMatrix\n[000]\n[000]' """ cdef long i else: for i from 0 <= i < self._nrows: out += '[]'
def _matrix_(self): """ Return a matrix version.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = Matrix(GF(2), [[1, 0], [0, 1]]) sage: A == BinaryMatrix(2, 2, A)._matrix_() True """ cdef long i, j
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation cdef BinaryMatrix B cdef long i
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows to ``k``. Preserves data. """ cdef long i, c self._M = <bitset_t* > sig_realloc(self._M, k * sizeof(bitset_t)) c = max(1, self._ncols) for i from self._nrows <= i < k: bitset_init(self._M[i], c) bitset_clear(self._M[i]) self._nrows = k
cdef LeanMatrix stack(self, LeanMatrix MM): """ Given ``A`` and ``B``, return [A] [B] """ cdef BinaryMatrix R cdef long i
cdef LeanMatrix augment(self, LeanMatrix MM): """ Given ``A`` and ``B``, return [A B] """ cdef BinaryMatrix R cdef long i, j
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation """ Return the matrix obtained by prepending an identity matrix. Special case of ``augment``. """ cdef long i, j
cpdef base_ring(self): """ Return `GF(2)`.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(4, 4) sage: A.base_ring() Finite Field of size 2 """ global GF2
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(3, 4) sage: A.characteristic() 2 """
cdef get_unsafe(self, long r, long c): global GF2_one, GF2_zero
cdef int set_unsafe(self, long r, long c, x) except -1: else:
cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
cdef inline bint get(self, long r, long c): # Not a Sage matrix operation
cdef inline void set(self, long x, long y): # Not a Sage matrix operation
cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation """ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes elsewhere.
Assumption (not checked): the entry in row ``x``, column ``y`` is nonzero to start with.
.. NOTE::
This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ cdef long i, j
cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation """ Return number of nonzero entries in row ``i``. """
cdef inline bint row_inner_product(self, long i, long j): # Not a Sage matrix operation """ Return the inner product between rows ``i`` and ``j``. """
cdef int add_multiple_of_row_c(self, long i, long j, s, bint col_start) except -1: """ Add row ``j`` to row ``i``. Other arguments are ignored. """
cdef int swap_rows_c(self, long i, long j) except -1:
cdef inline list nonzero_positions_in_row(self, long i): """ Get coordinates of nonzero entries of row ``r``. """ return bitset_list(self._M[i])
cdef inline list row_sum(self, object L): # Not a Sage matrix operation """ Return the mod-2 sum of the rows indexed by ``L``. """
cdef inline list row_union(self, object L): # Not a Sage matrix operation """ Return the ``or`` of the rows indexed by ``L``. """
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef BinaryMatrix T cdef long i, j
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Return the product ``self * other``. """ cdef BinaryMatrix M cdef long i, j
cdef LeanMatrix matrix_from_rows_and_columns(self, rows, columns): """ Return submatrix indexed by indicated rows and columns. """ cdef long r, c
cdef matrix_from_rows_and_columns_reordered(self, rows, columns): """ Return a submatrix indexed by indicated rows and columns, as well as the column order of the resulting submatrix. """ cdef long r, c, lc, lg cdef mp_bitcnt_t *cols # deal with trivial case return A, [] # write [c for c in columns if c<lc] as bitset `mask` and # write [c for c in columns if c>=lc] as array `cols` cdef bitset_t mask else: # write [ c for c in range(lc) if c not in columns] as array `gaps` cdef mp_bitcnt_t *gaps # copy relevant part of this matrix into A cdef bitset_t row, row2 # record order of the columns in list `order` # free up the two arrays and the bitset
cdef list _character(self, bitset_t x): # Not a Sage matrix operation """ Return the vector of intersection lengths of the rows with ``x``. """ cdef long i
cdef BinaryMatrix _distinguish_by(self, BinaryMatrix P): """ Helper method for equitable partition. """ cdef BinaryMatrix Q else:
cdef BinaryMatrix _splice_by(self, BinaryMatrix P): """ Helper method for equitable partition. """ cdef BinaryMatrix Q cdef long i, j, r
cdef BinaryMatrix _isolate(self, long j): """ Helper method for isomorphism test. """ cdef BinaryMatrix Q cdef long i, r Q = BinaryMatrix(self._nrows + 1, self._ncols) for i from 0 <= i < self._nrows: bitset_copy(Q._M[i], self._M[i]) bitset_discard(Q._M[i], j) bitset_add(Q._M[self._nrows], j) return Q
cdef BinaryMatrix equitable_partition(self, BinaryMatrix P=None): """ Compute an equitable partition of the columns. """
cdef bint is_isomorphic(self, BinaryMatrix other, BinaryMatrix s_eq=None, BinaryMatrix o_eq=None) except -2: # Not a Sage matrix operation """ Test for isomorphism between the row spaces. """ cdef long e, f, i, j s_eq = self.equitable_partition() o_eq = other.equitable_partition()
return False return False
for i from 0 <= i < s_eq.nrows(): if s_eq.row_len(i) != o_eq.row_len(i): return False for i from 0 <= i < s_eq.nrows(): if s_eq.row_len(i) > 1: break e = bitset_first(s_eq._M[i]) s_eq2 = self.equitable_partition(s_eq._isolate(e)) f = bitset_first(o_eq._M[i]) while f >= 0: if self.is_isomorphic(other, s_eq2, other.equitable_partition(o_eq._isolate(f))): return True f = bitset_next(o_eq._M[i], f + 1) return False
def __neg__(self): """ Negate the matrix.
In characteristic 2, this does nothing.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: B = -A # indirect doctest sage: B == A True """
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: B = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: C = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: D = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: E = BinaryMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j return NotImplemented # res gets inverted if matroids are deemed different. return not res
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = BinaryMatrix(2, 5) sage: A == loads(dumps(A)) # indirect doctest True sage: C = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: C == loads(dumps(C)) True """
cdef GF3, GF3_one, GF3_zero, GF3_minus_one
cdef class TernaryMatrix(LeanMatrix): """ Ternary matrix class. Entries are stored bit-packed into integers.
INPUT:
- ``m`` -- Number of rows. - ``n`` -- Number of columns. - ``M`` -- (default: ``None``) ``Matrix`` or ``TernaryMatrix`` instance. Assumption: dimensions of ``M`` are at most ``m`` by ``n``. - ``ring`` -- (default: ``None``) ignored.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 2, Matrix(GF(7), [[0, 0], [0, 0]])) sage: B = TernaryMatrix(2, 2, ring=GF(5)) sage: C = TernaryMatrix(2, 2) sage: A == B and A == C True """ def __cinit__(self, long m, long n, M=None, ring=None): """ Init internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j global GF3, GF3_zero, GF3_one, GF3_minus_one, GF3_not_defined
else:
def __init__(self, long m, long n, M=None, ring=None): """ See class docstring for full specification.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j for i from 0 <= i < M.nrows(): for j from 0 <= j < M.ncols(): s = int((<LeanMatrix>M).get_unsafe(i, j)) % 3 if s: bitset_add(self._M0[i], j) if s == 2: bitset_add(self._M1[i], j) return
def __dealloc__(self): cdef long i
def __repr__(self): r""" Return representation string
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) sage: repr(A) # indirect doctest '2 x 3 TernaryMatrix\n[000]\n[000]' """ cdef long i else: for i from 0 <= i < self._nrows: out += '[]'
def _matrix_(self): """ Return a matrix version.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = Matrix(GF(3), [[1, 0], [0, 1]]) sage: A == TernaryMatrix(2, 2, A)._matrix_() True """ cdef long i, j
cdef get_unsafe(self, long r, long c): global GF3_zero, GF3_one, GF3_minus_one
cdef int set_unsafe(self, long r, long c, x) except -1:
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation cdef TernaryMatrix T cdef long i
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows to ``k``. Preserves data. """ cdef long i self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t)) self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t)) c = max(1, self._ncols) for i from self._nrows <= i < k: bitset_init(self._M0[i], c) bitset_clear(self._M0[i]) bitset_init(self._M1[i], c) bitset_clear(self._M1[i]) self._nrows = k
cdef LeanMatrix stack(self, LeanMatrix MM): cdef TernaryMatrix R cdef TernaryMatrix M = <TernaryMatrix > MM cdef long i R = TernaryMatrix(self.nrows() + M.nrows(), self.ncols(), self) for i from 0 <= i < M.nrows(): bitset_copy(R._M0[i + self.nrows()], M._M0[i]) bitset_copy(R._M1[i + self.nrows()], M._M1[i]) return R
cdef LeanMatrix augment(self, LeanMatrix MM): cdef TernaryMatrix R cdef TernaryMatrix M = <TernaryMatrix > MM cdef long i, j R = TernaryMatrix(self.nrows(), self.ncols() + M.ncols(), self) for i from 0 <= i < R.nrows(): for j from 0 <= j < M.ncols(): bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j)) bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j)) return R
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation """ Return the matrix obtained by prepending an identity matrix.
Special case of ``augment``. """ cdef long i, j
cpdef base_ring(self): """ Return GF(3).
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(3, 3) sage: A.base_ring() Finite Field of size 3 """ global GF3
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(3, 4) sage: A.characteristic() 3 """
cdef inline long get(self, long r, long c): # Not a Sage matrix operation
cdef inline int set(self, long r, long c, x) except -1: # Not a Sage matrix operation
cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
cdef inline bint _is_negative(self, long r, long c):
cdef inline long row_len(self, long i): # Not a Sage matrix operation """ Return number of nonzero entries in row ``i``. """
cdef inline long row_inner_product(self, long i, long j): # Not a Sage matrix operation """ Return the inner product between rows ``i`` and ``j``. """ cdef long u
cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1: """ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is ignored. """ bitset_symmetric_difference(self._s, self._M0[x], self._M1[y]) bitset_symmetric_difference(self._t, self._M1[x], self._M0[y]) bitset_intersection(self._u, self._s, self._t) bitset_symmetric_difference(self._s, self._s, self._M1[x]) bitset_symmetric_difference(self._t, self._t, self._M1[y]) bitset_union(self._M0[x], self._s, self._t) bitset_copy(self._M1[x], self._u) else: # -1, since we assume no 0-multiple ever gets added. self.row_subs(x, y)
cdef void row_subs(self, long x, long y): # Not a Sage matrix operation """ Subtract row ``y`` from row ``x``. """
cdef void _row_negate(self, long x):
cdef int swap_rows_c(self, long x, long y) except -1:
cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation """ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes elsewhere.
Assumption (not checked): the entry in row ``x``, column ``y`` is nonzero to start with.
.. NOTE::
This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ cdef long i, j else:
cdef list nonzero_positions_in_row(self, long r): """ Get coordinates of nonzero entries of row ``r``. """
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef TernaryMatrix T cdef long i, j
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Return the product ``self * other``. """ cdef TernaryMatrix M cdef long i, j else:
cdef matrix_from_rows_and_columns_reordered(self, rows, columns): """ Return a submatrix indexed by indicated rows and columns, as well as the column order of the resulting submatrix. """ cdef long r, c, lc, lg cdef mp_bitcnt_t *cols # deal with trivial case return A, [] # write [c for c in columns if c<lc] as bitset `mask` and # write [c for c in columns if c>=lc] as array `cols` cdef bitset_t mask else: # write [ c for c in range(lc) if c not in columns] as array `gaps` cdef mp_bitcnt_t *gaps # copy relevant part of this matrix into A cdef bitset_t row0, row1, row0_2, row1_2 cdef mp_bitcnt_t p, q # record order of the columns in list `order` # free up the two arrays and the bitset
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]])) sage: B = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]])) sage: C = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]])) sage: D = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]])) sage: E = TernaryMatrix(2, 3, Matrix(GF(3), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j return NotImplemented return NotImplemented # res gets inverted if matroids are deemed different. return not res return not res
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = TernaryMatrix(2, 5) sage: A == loads(dumps(A)) # indirect doctest True sage: C = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]])) sage: C == loads(dumps(C)) True """
cdef class QuaternaryMatrix(LeanMatrix): """ Matrices over GF(4).
INPUT:
- ``m`` -- Number of rows - ``n`` -- Number of columns - ``M`` -- (default: ``None``) A QuaternaryMatrix or LeanMatrix or (Sage) Matrix instance. If not given, new matrix will be filled with zeroes. Assumption: ``M`` has dimensions at most ``m`` times ``n``. - ``ring`` -- (default: ``None``) A copy of GF(4). Useful for specifying generator name.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) sage: B = QuaternaryMatrix(2, 2, GenericMatrix(2, 2, ring=GF(4, 'x'))) sage: C = QuaternaryMatrix(2, 2, ring=GF(4, 'x')) sage: A == B and A == C True """ def __cinit__(self, long m, long n, M=None, ring=None): """ Init internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j
else:
def __init__(self, long m, long n, M=None, ring=None): """ See class docstring for full specification.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j else: raise TypeError("unrecognized input type.") else:
def __dealloc__(self): """ Free internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 sage: A = None """ cdef long i
def __repr__(self): r""" Return representation string
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) sage: repr(A) # indirect doctest '2 x 3 QuaternaryMatrix\n[000]\n[000]' """ cdef long i else: for i from 0 <= i < self._nrows: out += '[]'
def _matrix_(self): """ Return Sage Matrix version of ``self``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) sage: A._matrix_() [0 0 0] [0 0 0] """
cdef inline get(self, long r, long c): # Not a Sage matrix operation else: else: else:
cdef inline int set(self, long r, long c, x) except -1: # Not a Sage matrix operation
cdef get_unsafe(self, long r, long c):
cdef int set_unsafe(self, long r, long c, x) except -1:
cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation cdef QuaternaryMatrix T cdef long i
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows to ``k``. Preserves data. """ self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t)) self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t)) c = max(1, self._ncols) for i from self._nrows <= i < k: bitset_init(self._M0[i], c) bitset_clear(self._M0[i]) bitset_init(self._M1[i], c) bitset_clear(self._M1[i]) self._nrows = k
cdef LeanMatrix stack(self, LeanMatrix MM): cdef QuaternaryMatrix R cdef QuaternaryMatrix M = <QuaternaryMatrix > MM cdef long i R = QuaternaryMatrix(self.nrows() + M.nrows(), self.ncols(), self) for i from 0 <= i < self._nrows: bitset_copy(R._M0[i + self.nrows()], M._M0[i]) bitset_copy(R._M1[i + self.nrows()], M._M1[i]) return R
cdef LeanMatrix augment(self, LeanMatrix MM): cdef QuaternaryMatrix R cdef QuaternaryMatrix M = <QuaternaryMatrix > MM cdef long i, j R = QuaternaryMatrix(self.nrows(), self.ncols() + M.ncols(), self) for i from 0 <= i < R.nrows(): for j from 0 <= j < M.ncols(): bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j)) bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j)) return R
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation """ Return the matrix obtained by prepending an identity matrix. Special case of ``augment``. """ cdef long i, j
cpdef base_ring(self): """ Return copy of `GF(4)` with appropriate generator.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, ring=GF(4, 'f')) sage: A.base_ring() Finite Field in f of size 2^2 """
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(200, 5000, ring=GF(4, 'x')) sage: A.characteristic() 2 """
cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation """ Return number of nonzero entries in row ``i``. """ bitset_union(self._t, self._M0[i], self._M1[i]) return bitset_len(self._t)
cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation """ Return the inner product between rows ``i`` and ``j``. """ cdef bint a, b else: else: else:
cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1: """ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is ignored. """
cdef int swap_rows_c(self, long x, long y) except -1:
cdef inline int _row_div(self, long x, object s) except -1: """ Divide all entries in row ``x`` by ``s``. """ raise ZeroDivisionError
cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation """ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes elsewhere.
Assumption (not checked): the entry in row ``x``, column ``y`` is nonzero to start with.
.. NOTE::
This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ cdef long i, j
cdef list nonzero_positions_in_row(self, long r): """ Get coordinates of nonzero entries of row ``r``. """
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef QuaternaryMatrix T cdef long i, j
cdef void conjugate(self): # Not a Sage matrix operation """ Apply the nontrivial GF(4)-automorphism to the entries. """ cdef long i
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Return the product ``self * other``. """ cdef QuaternaryMatrix M, ot cdef long i, j
cdef matrix_from_rows_and_columns_reordered(self, rows, columns): """ Return a submatrix indexed by indicated rows and columns, as well as the column order of the resulting submatrix. """ cdef long r, c, lc, lg cdef mp_bitcnt_t *cols # deal with trivial case return A, [] # write [c for c in columns if c<lc] as bitset `mask` and # write [c for c in columns if c>=lc] as array `cols` cdef bitset_t mask else: # write [ c for c in range(lc) if c not in columns] as array `gaps` cdef mp_bitcnt_t *gaps # copy relevant part of this matrix into A cdef bitset_t row0, row1, row0_2, row1_2 cdef mp_bitcnt_t p, q # record order of the columns in list `order` # free up the two arrays and the bitset
def __neg__(self): """ Negate the matrix.
In characteristic 2, this does nothing.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]])) sage: B = -A # indirect doctest sage: B == A True """
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]])) sage: B = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]])) sage: C = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 1], [0, 1]])) sage: D = QuaternaryMatrix(2, 2, Matrix(GF(4, 'y'), [[1, 0], [0, 1]])) sage: E = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j return NotImplemented return NotImplemented # res gets inverted if matroids are deemed different. return not res return not res
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = QuaternaryMatrix(2, 5, ring=GF(4, 'x')) sage: A == loads(dumps(A)) # indirect doctest True sage: C = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 1], [0, 1]])) sage: C == loads(dumps(C)) True """
cpdef GenericMatrix generic_identity(n, ring): """ Return a GenericMatrix instance containing the `n \times n` identity matrix over ``ring``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = generic_identity(2, QQ) sage: Matrix(A) [1 0] [0 1] """ cdef long i
# Integer matrices
cdef class IntegerMatrix(LeanMatrix): """ Matrix over the integers.
INPUT:
- ``nrows`` -- number of rows - ``ncols`` -- number of columns - ``M`` -- (default: ``None``) a ``Matrix`` or ``GenericMatrix`` of dimensions at most ``m*n``.
.. NOTE::
This class is intended for internal use by the LinearMatroid class only. Hence it does not derive from ``SageObject``. If ``A`` is a LeanMatrix instance, and you need access from other parts of Sage, use ``Matrix(A)`` instead.
This class is mainly intended for use with the RegularMatroid class, so entries are assumed to be small integers. No overflow checking takes place!
EXAMPLES::
sage: M = Matroid(graphs.CompleteGraph(4).incidence_matrix(oriented=True), ....: regular=True) # indirect doctest sage: M.is_isomorphic(matroids.Wheel(3)) True """ def __cinit__(self, long nrows, long ncols, M=None, ring=None): """ Init internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 2, Matrix(GF(4, 'x'), ....: [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 """ cdef long i, j
def __init__(self, long nrows, long ncols, M=None, ring=None): """ See class docstring for full information.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 2, Matrix(GF(3), ....: [[0, 0], [0, 0]])) # indirect doctest sage: B = IntegerMatrix(2, 2) sage: A == B True """ cdef long i, j for i from 0 <= i < M.nrows(): for j from 0 <= j < M.ncols(): self._entries[i * self._ncols + j] = int((<LeanMatrix>M).get_unsafe(i, j)) else: # Sage Matrix or otherwise
def __dealloc__(self): """ Free internal data structures.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 2, Matrix(GF(4, 'x'), ....: [[0, 0], [0, 0]])) # Indirect doctest sage: A.nrows() 2 sage: A = None """
def __repr__(self): """ Return representation.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]])) sage: repr(A) # indirect doctest 'IntegerMatrix instance with 2 rows and 2 columns' """
cdef inline get(self, long r, long c): # Not a Sage matrix operation
cdef inline void set(self, long r, long c, int x): # Not a Sage matrix operation
cdef get_unsafe(self, long r, long c): """ Return a Sage Integer, for safety down the line when dividing.
EXAMPLES:
By returning an Integer rather than an int, the following test no longer fails::
sage: from sage.matroids.advanced import * sage: M = RegularMatroid(matrix([ ....: (1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0), ....: (0, 1, 0, 0, -1, 1, 0, 0, 0, 0, 0), ....: (0, 0, 1, 0, 0, -1, 1, 0, 0, 1, 0), ....: (0, 0, 0, 1, 0, 0, -1, 1, 0, 0, 0), ....: (0, 0, 0, 0, 0, 0, -1, 0, 1, -1, 0), ....: (0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1)])) sage: all(N.is_valid() for N in M.linear_extensions(F=[4, 10])) True """
cdef int set_unsafe(self, long r, long c, x) except -1:
cdef bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
cdef int resize(self, long k) except -1: # Not a Sage matrix operation """ Change number of rows to ``k``. Preserves data. """ cdef long l = self._ncols * (self._nrows - k) if l > 0: sig_realloc(self._entries, self._ncols * k * sizeof(int)) memset(self._entries + self._nrows * self._ncols, 0, l * self._ncols * sizeof(int)) elif l < 0: sig_realloc(self._entries, self._ncols * k * sizeof(int)) self._nrows = k return 0
cdef LeanMatrix stack(self, LeanMatrix M): """ Warning: assumes ``M`` is an IntegerMatrix instance of right dimensions! """ cdef IntegerMatrix A A = IntegerMatrix(self._nrows + M.nrows(), self._ncols) memcpy(A._entries, self._entries, self._nrows * self._ncols * sizeof(int)) memcpy(A._entries + self._nrows * self._ncols, (<IntegerMatrix>M)._entries, M.nrows() * M.ncols() * sizeof(int)) return A
cdef LeanMatrix augment(self, LeanMatrix M): """ Warning: assumes ``M`` is a GenericMatrix instance! """ cdef IntegerMatrix A cdef long i cdef long Mn = M.ncols() A = IntegerMatrix(self._nrows, self._ncols + Mn) for i from 0 <= i < self._nrows: memcpy(A._entries + i * A._ncols, self._entries + i * self._ncols, self._ncols * sizeof(int)) memcpy(A._entries + (i * A._ncols + self._ncols), (<IntegerMatrix>M)._entries + i * Mn, Mn * sizeof(int)) return A
cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation cdef IntegerMatrix A = IntegerMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring) cdef long i for i from 0 <= i < self._nrows: A._entries[i * A._ncols + i] = 1 memcpy(A._entries + (i * A._ncols + self._nrows), self._entries + i * self._ncols, self._ncols * sizeof(int)) return A
cpdef base_ring(self): """ Return the base ring of ``self``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(3, 4) sage: A.base_ring() Integer Ring """
cpdef characteristic(self): """ Return the characteristic of ``self.base_ring()``.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = GenericMatrix(3, 4) sage: A.characteristic() 0 """ return 0
cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation """ Return number of nonzero entries in row ``i``. """ cdef long k cdef long res = 0 for k from 0 <= k < self._ncols: if self.get(i, k): res += 1 return res
cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation """ Return the inner product between rows ``i`` and ``j``. """ cdef long k cdef int res = 0 for k from 0 <= k < self._ncols: res += self.get(i, k) * self.get(j, k) return res
cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1: """ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is ignored. """ cdef long i for i from 0 <= i < self._ncols: self.set(x, i, self.get(x, i) + self.get(y, i)) else:
cdef int swap_rows_c(self, long x, long y) except -1: """ Swap rows ``x`` and ``y``. """ cdef int* tmp raise MemoryError
cdef int rescale_row_c(self, long x, s, bint col_start) except -1: """ Scale row ``x`` by ``s``. Argument ``col_start`` is for Sage compatibility, and is ignored. """ cdef long i
cdef int rescale_column_c(self, long y, s, bint start_row) except -1: """ Scale column ``y`` by ``s``. Argument ``start_row`` is for Sage compatibility, and is ignored. """ cdef long j for j from 0 <= j < self._nrows: self.set(j, y, self.get(j, y) * s) return 0
cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation """ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes elsewhere.
Assumption (not checked): the entry in row ``x``, column ``y`` is invertible (so 1 or -1) to start with.
.. NOTE::
This is different from what matroid theorists tend to call a pivot, as it does not involve a column exchange! """ cdef long i, j cdef int a, s a = self.get(x, y) # 1 or -1, so inverse is equal to itself self.rescale_row_c(x, a, 0) for i from 0 <= i < self._nrows: s = self.get(i, y) if s and i != x: self.add_multiple_of_row_c(i, x, -s, 0) return 0
cdef list nonzero_positions_in_row(self, long r): """ Get coordinates of nonzero entries of row ``r``. """ cdef long j cdef list res = [] for j from r * self._ncols <= j < (r + 1) * self._ncols: if self._entries[j]: res.append(j - r * self._ncols) return res
cdef LeanMatrix transpose(self): """ Return the transpose of the matrix. """ cdef IntegerMatrix A cdef long i, j
cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other): """ Return the product ``self * other``. """ cdef IntegerMatrix A, ot cdef long i, j, t ot = <IntegerMatrix > other A = IntegerMatrix(self._nrows, ot._ncols) for i from 0 <= i < A._nrows: for j from 0 <= j < A._ncols: s = 0 for t from 0 <= t < self._ncols: s += self.get(i, t) * ot.get(t, j) A.set(i, j, s) return A
cdef list gauss_jordan_reduce(self, columns): # Not a Sage matrix operation """ Row-reduce so the lexicographically first basis indexes an identity submatrix. """ cdef long a, c, p, row cdef bint is_pivot raise ValueError("not a totally unimodular matrix")
def __richcmp__(left, right, op): """ Compare two matrices.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: B = IntegerMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]])) sage: C = IntegerMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: D = IntegerMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]])) sage: E = IntegerMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]])) sage: A == B # indirect doctest True sage: A != C # indirect doctest True sage: A == D # indirect doctest False sage: E == A False """ cdef long i, j return NotImplemented return NotImplemented # res gets inverted if matroids are deemed different. return not res
def __reduce__(self): """ Save the object.
EXAMPLES::
sage: from sage.matroids.lean_matrix import * sage: A = IntegerMatrix(2, 5) sage: A == loads(dumps(A)) # indirect doctest True sage: C = IntegerMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]])) sage: C == loads(dumps(C)) True """ cdef long i |