Skip to content

Commit

Permalink
Add FieldArray.null_space() method
Browse files Browse the repository at this point in the history
  • Loading branch information
mhostetter committed Feb 12, 2022
1 parent 2669826 commit 71dd31c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 31 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ GF([[191, 33, 85, 77, 88],
The `galois` package intercepts relevant calls to NumPy's linear algebra functions and performs the specified
operation in `GF(p^m)` not in **R**. Some of these functions include:

- `np.dot`, `np.vdot`, `np.inner`, `np.outer`, `np.matmul`, `np.linalg.matrix_power`
- `np.linalg.det`, `np.linalg.matrix_rank`, `np.trace`
- `np.linalg.solve`, `np.linalg.inv`
- `np.dot()`, `np.vdot()`, `np.inner()`, `np.outer()`, `np.matmul()`, `np.linalg.matrix_power()`
- `np.linalg.det()`, `np.linalg.matrix_rank()`, `np.trace()`
- `np.linalg.solve()`, `np.linalg.inv()`

```python
>>> A = GF256.Random((3,3)); A
Expand All @@ -268,7 +268,8 @@ True

Galois field arrays also contain matrix decomposition routines and matrix vector spaces not included in NumPy. These include:

- `FieldArray.row_reduce`, `FieldArray.lu_decompose`, `FieldArray.plu_decompose`, `FieldArray.row_space()`, `FieldArray.column_space()`, `FieldArray.left_null_space()`
- `FieldArray.row_reduce()`, `FieldArray.lu_decompose()`, `FieldArray.plu_decompose()`
- `FieldArray.row_space()`, `FieldArray.column_space()`, `FieldArray.left_null_space()`, `FieldArray.null_space()`

#### NumPy ufunc methods

Expand Down
3 changes: 2 additions & 1 deletion docs/basic-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ operation in :math:`\mathrm{GF}(p^m)` not in :math:`\mathbb{R}`. Some of these f
Galois field arrays also contain matrix decomposition routines and matrix vector spaces not included in NumPy. These include:

- :func:`galois.FieldArray.row_reduce`, :func:`galois.FieldArray.lu_decompose`, :func:`galois.FieldArray.plu_decompose`, :func:`galois.FieldArray.row_space`, :func:`galois.FieldArray.column_space`, :func:`galois.FieldArray.left_null_space`
- :func:`galois.FieldArray.row_reduce`, :func:`galois.FieldArray.lu_decompose`, :func:`galois.FieldArray.plu_decompose`
- :func:`galois.FieldArray.row_space`, :func:`galois.FieldArray.column_space`, :func:`galois.FieldArray.left_null_space`, :func:`galois.FieldArray.null_space`

NumPy ufunc methods
...................
Expand Down
11 changes: 11 additions & 0 deletions galois/_fields/_linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,14 @@ def left_null_space(A):
LN, _ = row_reduce(LN)

return LN


def null_space(A):
"""
x = N(A) = LN(A^T)
A x = 0
"""
if not A.ndim == 2:
raise ValueError(f"Only 2-D matrices have a null space, not {A.ndim}-D.")

return left_null_space(A.T)
81 changes: 55 additions & 26 deletions galois/_fields/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .._prime import divisors

from ._dtypes import DTYPES
from ._linalg import dot, row_reduce, lu_decompose, plu_decompose, row_space, column_space, left_null_space
from ._linalg import dot, row_reduce, lu_decompose, plu_decompose, row_space, column_space, left_null_space, null_space
from ._functions import FunctionMeta
from ._ufuncs import UfuncMeta

Expand Down Expand Up @@ -2003,38 +2003,26 @@ def column_space(self) -> "FieldArray":
Notes
-----
Given a :math:`m \times n` matrix :math:`\mathbf{A}` over :math:`\mathrm{GF}(q)`, the *column space* of :math:`\mathbf{A}`
Given an :math:`m \times n` matrix :math:`\mathbf{A}` over :math:`\mathrm{GF}(q)`, the *column space* of :math:`\mathbf{A}`
is the vector space :math:`\{\mathbf{x} \in \mathrm{GF}(q)^m\}` defined by all linear combinations of the columns
of :math:`\mathbf{A}`. The column space has at most dimension :math:`n`.
of :math:`\mathbf{A}`. The column space has at most dimension :math:`\textrm{min}(m, n)`.
The column space has properties :math:`C(\mathbf{A}) = R(\mathbf{A}^T)`.
The column space has properties :math:`\mathcal{C}(\mathbf{A}) = \mathcal{R}(\mathbf{A}^T)` and
:math:`\textrm{dim}(\mathcal{C}(\mathbf{A})) + \textrm{dim}(\mathcal{N}(\mathbf{A})) = n`.
Examples
--------
The :func:`column_space` method defines basis vectors (its rows) that span the column space :math:`\mathbf{A}`.
The :func:`column_space` method defines basis vectors (its rows) that span the column space of :math:`\mathbf{A}`.
The dimension of the column space and null space sum to :math:`n`.
.. ipython:: python
GF = galois.GF(2**8)
A = GF.Random((2,3)); A
A.column_space()
If all of the columns are linearly dependent, then the column space has dimension 1.
.. ipython:: python
# Column 2 is a multiple of Column 1
A[:,1] = GF.Random() * A[:,0]
# Column 3 is a multiple of Column 1
A[:,2] = GF.Random() * A[:,0]
A.column_space()
Zero matrices have an empty column space with dimension 0.
.. ipython:: python
A = GF.Zeros((2,3)); A
A.column_space()
m, n = 3, 5
GF = galois.GF(31)
A = GF.Random((m, n)); A
C = A.column_space(); C
N = A.null_space(); N
C.shape[0] + N.shape[0] == n
"""
return column_space(self)

Expand All @@ -2051,7 +2039,7 @@ def left_null_space(self) -> "FieldArray":
Notes
-----
Given an :math:`m \times n` matrix :math:`\mathbf{A}` over :math:`\mathrm{GF}(q)`, the *left null space* of :math:`\mathbf{A}`
is the vector space :math:`\{\mathbf{x} \in \mathrm{GF}(q)^m\}` that annihilate the rows of :math:`\mathbf{A}`, i.e.
is the vector space :math:`\{\mathbf{x} \in \mathrm{GF}(q)^m\}` that annihilates the rows of :math:`\mathbf{A}`, i.e.
:math:`\mathbf{x}\mathbf{A} = \mathbf{0}`.
The left null space has properties :math:`\mathcal{LN}(\mathbf{A}) = \mathcal{N}(\mathbf{A}^T)` and
Expand Down Expand Up @@ -2079,6 +2067,47 @@ def left_null_space(self) -> "FieldArray":
"""
return left_null_space(self)

def null_space(self) -> "FieldArray":
r"""
Computes the null space of the matrix :math:`\mathbf{A}`.
Returns
-------
galois.FieldArray
The null space basis matrix. The rows of the basis matrix are the basis vectors that span the null space.
The number of rows of the basis matrix is the dimension of the null space.
Notes
-----
Given an :math:`m \times n` matrix :math:`\mathbf{A}` over :math:`\mathrm{GF}(q)`, the *null space* of :math:`\mathbf{A}`
is the vector space :math:`\{\mathbf{x} \in \mathrm{GF}(q)^n\}` that annihilates the columns of :math:`\mathbf{A}`, i.e.
:math:`\mathbf{A}\mathbf{x} = \mathbf{0}`.
The null space has properties :math:`\mathcal{N}(\mathbf{A}) = \mathcal{LN}(\mathbf{A}^T)` and
:math:`\textrm{dim}(\mathcal{C}(\mathbf{A})) + \textrm{dim}(\mathcal{N}(\mathbf{A})) = n`.
Examples
--------
The :func:`null_space` method defines basis vectors (its rows) that span the null space of :math:`\mathbf{A}`.
The dimension of the column space and null space sum to :math:`n`.
.. ipython:: python
m, n = 3, 5
GF = galois.GF(31)
A = GF.Random((m, n)); A
C = A.column_space(); C
N = A.null_space(); N
C.shape[0] + N.shape[0] == n
The null space is the set of vectors that sum the columns to 0.
.. ipython:: python
A @ N.T
"""
return null_space(self)

def field_trace(self) -> "FieldArray":
r"""
Computes the field trace :math:`\mathrm{Tr}_{L / K}(x)` of the elements of :math:`x`.
Expand Down

0 comments on commit 71dd31c

Please sign in to comment.