Sparse binary linear algebra

Binary matrix

class pyqec.sparse.BinaryMatrix

A sparse binary matrix with efficient row access.

Parameters
  • num_columns (Int) – The number of columns in the matrix. Must be a non-negative integer.

  • rows (Seq[Seq[Int]]) – Each sequence in the outer sequence represents a row of the matrix. The inner sequences contain the positions (columns) of entries with value 1 in the corresponding row.

Example

>>> from pyqec.sparse import BinaryMatrix, to_dense
>>> matrix = BinaryMatrix(3, [[0, 2], [1], [0, 1]])
>>> to_dense(matrix)
array([[1, 0, 1],
       [0, 1, 0],
       [1, 1, 0]], dtype=int32)
Raises
  • If the number of columns is negative or

  • if a position in a row is out of bound.

bitwise_xor(other)

Returns the bitwise xor sum of self and other.

Example

>>> from pyqec.sparse import BinaryMatrix, BinaryVector
>>> matrix1 = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3], [1, 2]])
>>> matrix2 = BinaryMatrix(4, [[0, 1], [1, 2], [0, 1, 3]])
>>> matrix.bitwise_xor(matrix2)
[2]
[3]
[0, 2, 3]
Raises

ValueError – The shapes of the matrices are different.

dot_with_matrix(matrix)

Returns the dot product between self and the given matrix.

Example

>>> from pyqec.sparse import BinaryMatrix, BinaryVector
>>> matrix1 = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3], [1, 2]])
>>> matrix2 = BinaryMatrix(3, [[0, 1], [1, 2], [0, 1], [1, 2])
>>> matrix.dot_with_matrix(matrix2)
[1, 2]
[0, 1]
[0, 2]
Raises

ValueError – Number of columns of self is not the same as the number of rows of the other matrix.

dot_with_vector(vector)

Returns the dot product between self and the given vector.

Example

>>> from pyqec.sparse import BinaryMatrix, BinaryVector
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3], [1, 2]])
>>> vector = BinaryVector(4, [1, 3])
>>> matrix.dot_with_vector(vector)
[0, 2]
Raises

ValueError – The vector length is not the same as the matrix number of columns.

echelon_form()

Performs Gaussian elimination to return the matrix in echelon form.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 3], [0, 2], [0, 2, 3]])
>>> matrix.echelon_form()
[0, 1, 2]
[1, 3]
[3]
element(row, column)

Returns the element at the given row and column.

Raises

IndexError – The row or column is out of bound.

static empty()

An empty matrix.

Mostly useful as a placeholder since it allocate a minimal amount of memory.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix.empty()
>>> matrix.num_rows()
0
>>> matrix.num_columns()
0
horizontal_concat_with(other)

Returns the horizontal concatenation of self and other matrix.

If the matrices have a different number of rows, the smallest one is padded with zeros.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3]])
>>> matrix.horizontal_concat_with(BinaryMatrix.identity(3))
[0, 1, 2, 4]
[1, 2, 3, 5]
[6]
static identity(length)

An identity matrix of the given length.

Example

>>> from pyqec.sparse import BinaryMatrix, to_dense
>>> matrix = BinaryMatrix.identity(3)
>>> to_dense(matrix)
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]], dtype=int32)
is_empty()

Checks if the matrix has shape (0, 0).

is_one_at(row, column)

Check if the given element has value 1.

Raises

IndexError – The row or column is out of bound.

is_zero()

Checks if all the elements have value 0.

is_zero_at(row, column)

Check if the given element has value 0.

Raises

IndexError – The row or column is out of bound.

nullspace()

Returns an orthogonal matrix where the rows generate the nullspace of self.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3]])
>>> matrix.nullspace()
[1, 2]
[0, 1, 3]
num_columns()

Returns the number of columns in the matrix.

num_ones()

Returns the number of elements with value 1.

num_rows()

Returns the number of rows in the matrix.

num_zeros()

Returns the number of elements with value 0.

rank()

Computes the number of linearly independent rows (or columns) of the matrix.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 3], [0, 2], [0, 2, 3]])
>>> matrix.rank()
3
row(row)

Returns the given row as a BinaryVector.

Raises

IndexError – The row is out of bound.

rows()
>>> from pyqec.sparse import BinaryMatrix, to_dense
>>> matrix = BinaryMatrix(3, [[0, 2], [1], [0, 1]])
>>> for row in matrix.rows():
...    print(row)
[0, 2]
[1]
[0, 1]
shape()

Returns a tuple of the numbers of rows and columns.

transposed()

Returns the transpose of the matrix.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(3, [[0, 2], [1], [0, 1]])
>>> matrix.transpose()
[0, 2]
[1, 2]
[0]
vertical_concat_with(other)

Returns the vertical concatenation of self and other matrix.

If the matrices have a different number of columns, the smallest one is padded with zeros.

Example

>>> from pyqec.sparse import BinaryMatrix
>>> matrix = BinaryMatrix(4, [[0, 1, 2], [1, 2, 3]])
>>> matrix.vertical_concat_with(BinaryMatrix.identity(3))
[0, 1, 2]
[1, 2, 3]
[0]
[1]
[2]
static zeros(num_rows, num_columns)

A matrix filled with zeros.

Example

>>> from pyqec.sparse import BinaryMatrix, to_dense
>>> matrix = BinaryMatrix.zeros(2, 3)
>>> to_dense(matrix)
array([[0, 0, 0],
       [0, 0, 0]], dtype=int32)

Binary vector

class pyqec.sparse.BinaryVector

A sparse binary vector.

Parameters
  • length (Int) – The number of elements in the vector. Must be a non-negative integer.

  • positions (Seq[Int]) – The positions of entries with value 1.

Example

>>> from pyqec.sparse import BinaryVector, to_dense
>>> vector = BinaryVector(3, [0, 2])
>>> to_dense(vector)
array([1, 0, 1], dtype=int32)
Raises

ValueError – If the length is negative or if a position is out of bound.

bitwise_xor(other)

Computes the bitwise xor sum of two vectors.

Example

>>> from pyqec.sparse import BinaryVector
>>> left = BinaryVector(5, [0, 2, 4])
>>> right = BinaryVector(5, [1, 2, 3])
>>> left.bitwise_xor(right)
[0, 1, 3, 4]
Raises

ValueError – If the vectors have different lengths.

concat(other)

Concatenates self with other.

Example

>>> from pyqec.sparse import BinaryVector
>>> left = BinaryVector(5, [0, 2, 4])
>>> right = BinaryVector(4, [1, 3])
>>> left.concat(right)
[0, 2, 4, 6, 8]
dot_with_matrix(matrix)

Computes the dot product between self and a matrix.

This assume that the vector is in row shape and compute v * M.

Example

>>> from pyqec.sparse import BinaryVector, PyBinaryMatrix
>>> vector = BinaryVector(3, [0, 2])
>>> matrix = PyBinaryMatrix(4, [[0, 3]], [0, 1, 2], [1, 3]])
>>> vector.dot_with_matrix(matrix)
[0, 1]
Raises

ValueError – If the vector length is the not the same as the matrix number of rows.

dot_with_vector(other)

Computes the dot product between two vectors.

Example

>>> from pyqec.sparse import BinaryVector
>>> left = BinaryVector(5, [0, 2, 4])
>>> right = BinaryVector(5, [1, 3])
>>> left.dot_with_vector(right)
0
Raises

ValueError – If the vectors have different length.

element(position)

Returns the value of the element at the given position.

Raises

IndexError – The position is out of bound.

static empty()

Constructs a vector of length 0.

This is useful as a placeholder since it allocates a minimal amount of memory.

is_empty()

Checks if the length of the vector is 0.

is_one_at(position)

Checks if the element at the given position is one.

Raises

IndexError – The position is out of bound.

is_zero()

Checks if all elements are 0.

is_zero_at(position)

Checks if the element at the given position is zero.

Raises

IndexError – The position is out of bound.

len()

Returns the number of elements in the vector.

non_trivial_position(index)

Index the given value in the list of non-trivial positions.

Example

>>> from pyqec.sparse import BinaryVector
>>> vector = BinaryVector(5, [0, 2, 4])
>>> vector.non_trivial_position(0)
0
>>> vector.non_trivial_position(1)
2
>>> vector.non_trivial_position(2)
4
Raises

IndexError – The index is greater or equal to the weight.

weight()

Returns the number of elements with value 1.

static zeros(length)

Constructs a vector of the given length filled with zeros.

Conversion to Numpy

pyqec.sparse.to_dense(sparse_bin_array)

Converts a sparse matrix or vector to a dense numpy representation.

Parameters

sparse_bin_array (Union[BinaryMatrix, BinaryVector]) – The array to convert.

Example

>>> from pyqec.sparse import BinaryMatrix, to_dense
>>> to_dense(BinaryMatrix.identity(3))
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]], dtype=int32)

General operations

pyqec.sparse.dot(left, right)

Computes the dot product between two sparse binary arrays.

Parameters

Examples

>>> from pyqec.sparse import BinaryMatrix, BinaryVector, dot
>>> matrix1 = BinaryMatrix(3, [[0, 1], [1, 2]])
>>> matrix2 = BinaryMatrix(2, [[0], [1], [0, 1]])
>>> dot(matrix1, matrix2)
[0, 1]
[0]
>>> vector = BinaryVector(3, [0, 2])
>>> dot(matrix1, vector)
[0, 1]
>>> dot(vector, matrix2)
[1]