# Computing the Nullspace

In [16]:
import numpy as np
import numpy.linalg as la

In [17]:
n = 5
np.random.seed(25)
A = np.random.randn(n, n)

# Decrease the rank
A[4] = A[0] + 5 * A[2]
A[1] = 3 * A[0] -2 * A[3]

In [18]:
from m_echelon import m_echelon

In [29]:
M, U = m_echelon(A.T)

In [30]:
la.norm(
M.dot(A.T) - U)

Out[30]:
1.2599818366099757e-15

In [31]:
U.round(3)

Out[31]:
array([[  1.027,   0.676,  -0.232,   1.202,  -0.135],
[  0.   ,  -3.498,  -1.468,   1.749,  -7.342],
[  0.   ,   0.   ,  -2.14 ,   0.   , -10.699],
[  0.   ,   0.   ,   0.   ,   0.   ,  -0.   ],
[  0.   ,   0.   ,   0.   ,   0.   ,  -0.   ]])


Now define NUT as vectors spanning the nullspace of $N(U^T)$.

In [32]:
NUT = np.eye(n)[:, 3:]
NUT

Out[32]:
array([[ 0.,  0.],
[ 0.,  0.],
[ 0.,  0.],
[ 1.,  0.],
[ 0.,  1.]])


Check that it's actually a nullspace:

In [33]:
U.T.dot(NUT)

Out[33]:
array([[  0.000e+00,   0.000e+00],
[  0.000e+00,   0.000e+00],
[  0.000e+00,   0.000e+00],
[  3.644e-16,   6.163e-33],
[ -1.776e-15,  -2.174e-16]])


Now define NA as some vectors spanning $N(A)$:

In [34]:
NA = M.T.dot(NUT)


And check:

In [35]:
A.dot(NA)

Out[35]:
array([[  1.110e-16,  -1.110e-16],
[  4.441e-16,  -4.441e-16],
[ -2.220e-16,  -5.551e-17],
[  1.110e-16,   1.110e-16],
[ -8.882e-16,  -6.661e-16]])

In []: