pythonnumpyscipylinear-algebra

how do I find the dimension of the span of the intersection/union of two null spaces of different sizes of matrices using numpy/scipy?


I need to find $dim(span(H\cap G))$ and $dim(span(H\cup G))$ where H and G are defined the following way:

enter image description here

I have no idea how to find the intersection/union of their null spaces and after that, I don't know how to find the span and dim.

matrix A has sizes of 5X18, and matrix B - 8X18.

This is what I tried using the null_space of Scipy; it seems like it does find the null spaces but fails in the intersection part, and I didn't find a dedicated intersection/union function.

import numpy as np
import sympy as sp
from sympy import *
from scipy.linalg import null_space

A = np.matrix([[2 ,0 ,3 ,-1 ,2 ,-1 ,6 ,-4 ,7 ,8 ,-1 ,-4 ,7 ,0 ,0 ,0 ,0 ,7 ],
               [-6 ,-7 ,-9 ,10 ,1 ,10 ,-4 ,12 ,-7 ,4 ,-4 ,5 ,-7 ,0 ,0 ,0 ,7 ,0 ],
               [10 ,0 ,8 ,-12 ,-4 ,-5 ,-5 ,-13 ,0 ,5 ,2 ,1 ,0 ,0 ,0 ,7 ,0 ,0],
               [8 ,0 ,5 ,-4 ,1 ,-4 ,3 ,-9 ,7 ,11 ,3 ,-2 ,7 ,0 ,7 ,0 ,0 ,0 ],
               [-9 ,-7 ,-3 ,8 ,5 ,8 ,1 ,11 ,0 ,-1 ,1 ,-3 ,0 ,7 ,0 ,0 ,0 ,0 ]])

B = np.matrix([[3 ,2 ,3 ,-1 ,5 ,-5 ,2 ,0 ,-3 ,5 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,2 ],
             [39 ,26 ,27 ,-13 ,29 ,-25 ,-4 ,-2 ,-7 ,21 ,0 ,0 ,0 ,0 ,0 ,0 ,32 ,0 ],
             [-5 ,18 ,31 ,-9 ,25 ,-5 ,12 ,-26 ,5 ,17 ,0 ,0 ,0 ,0 ,0 ,32 ,0 ,0 ],
             [25 ,6 ,21 ,-3 ,19 ,-23 ,4 ,-14 ,-9 ,27 ,0 ,0 ,0 ,0 ,16 ,0 ,0 ,0 ],
             [-3 ,-6 ,-3 ,1 ,-5 ,1 ,-4 ,2 ,3 ,-1 ,0 ,0 ,0 ,4 ,0 ,0 ,0 ,0 ],
             [-47 ,-10 ,-35 ,5 ,-53 ,17 ,4 ,-14 ,79 ,-13 ,0 ,0 ,32 ,0 ,0 ,0 ,0 ,0 ],
             [67 ,66 ,71 ,-33 ,81 ,-61 ,76 ,-10 ,-67 ,41 ,0 ,32 ,0 ,0 ,0 ,0 ,0 ,0 ],
             [59 ,18 ,31 ,-41 ,57 ,-37 ,12 ,6 ,-59 ,49 ,32 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ]])

An = null_space(A)
Bn = null_space(B)

intersect = An[np.where(An==Bn)]
print(intersect)

Solution

  • The intersection of the null spaces is spanned by a set of vectors vi for which both A @ vi = 0 and B @ vi = 0, where 0 represents a zero vector of appropriate size. You can find the vi by stacking the two matrices and taking the null space.

    Cn = null_space(np.vstack((A, B)))
    np.testing.assert_allclose(A @ Cn, 0, atol=5e-14)
    np.testing.assert_allclose(B @ Cn, 0, atol=5e-14)
    # both tests pass
    

    You can get a set of vectors that spans the union of the null spaces by pooling the null space vectors (i.e. stacking the An and Bn that you found).

    np.vstack((An.T, Bn.T))
    

    In general, however, these vectors will not be linearly independent. If you want a minimal set of vectors that span the union of the null spaces, the most concise way I can think of is to take the null space of the null space of these vectors.

    Dn = null_space(null_space(np.vstack((An.T, Bn.T))).T)
    

    np.linalg.matrix_rank finds the dimensionality of the span of a set of vectors.

    # note that it doesn't matter whether we transpose or not
    np.linalg.matrix_rank(Cn)  # 7
    np.linalg.matrix_rank(Dn)  # 16
    

    If you just needed the dim of the span of the union, you don't really need to remove the redundancies before taking the rank.

    np.linalg.matrix_rank(np.vstack((An.T, Bn.T)))  # 16
    

    Of course, there are probably more revealing/satisfying solutions using explicit matrix decompositions, but this is the most concise way I can think of.