Search code examples
pythonnumpyscipylinear-algebrasolver

scipy solve with unknowns in both vectors


I'm currently trying to implement a finite element method in Python and I have to solve a linear system where the matrix is under determined, but the system should be well-defined by the boundary condition.

To be precise, in a very simple case, the matrix looks like this

[ 12.,   6., -12.,   6.],
[  6.,   4.,  -6.,   2.],
[-12.,  -6.,  12.,  -6.],
[  6.,   2.,  -6.,   4.]]

And the right-hand side is just an array of numbers.

Obviously, the third column is the negative of the first, so the matrix is under determined.

However, I want to impose that the first entry in the solution vector is zero, so the solution should be of the form [0,x,y,z]. Now we have 3 unknowns and 3 equations, so there should be a unique solution, but I haven't found a scipy function that does that, since the normal scipy.linalg.solve only takes the matrix and the right-hand side as inputs.

I've tried to rewrite the linear system, but in some cases there are undefined variables in the right-hand side as well and more set values in the unknown vector, so I'm looking for a procedure that solves an any linear system with the matrix, and two vectors with unknowns.


Solution

  • Problem Statement

    You're question is a bit confusing because your matrix has rank 2 and not 3 (this means it gives you only 2 linearly independent equations). Now if I call your matrix A and the right hand side b the best you can hope for is a solution of the form

    A@[0,0,x,y]=b.
    

    Keep in mind that this does not always work. Indeed since the last two columns of A are linearly independent this solution exists if and only if b is in the image of A. So b must come from some multiplication of A with a vector.

    Linear Algebra Idea

    Now if we remember one simple fact from linear algebra we can find you a solution in the form you hope for. We can write any solution x to an underdetermined linear equation as x=v+n with v being any solution and n being from the null space of the matrix. So we just find a solution that is not in the form yet and then bring it into the form by moving it threw the null space of A.

    Example

    Let's go thew an explicit example: suppose we have

    b=[12,4,-12,8](=A@[1,2,3,4]).
    

    (Of course I assume here we don't know that b=A@[1,2,3,4].) We can find a solution with v=np.linalg.lstsq(A, b)[0](=[ 0.4, -0.8, -0.4, 1.2]). Here we should double check that A@v==b (or at least that np.isclose(A@v,b)) since np.linalg.lstsq does not throw an exception if no solution exists but gives you an approximate one.

    If now you want a different solution in your special form you just calculate the null space

    null_space = scipy.linalg.null_space(A)
    

    and then how we have to change v to get it to be zero in the first two entries

    coefs = np.linalg.solve(null_space[:2], v[:2])
    w = -null_space@coefs
    x = v+w.
    

    Turns out x=[0,0,0,2].