Solving Linear Systems

Many calculations involve solving systems of linear equations. In many cases, you will find it convenient to write down the equations explicitly, and then solve them using (RefLink[Solve, paclet:ref/Solve]).

In some cases, however, you may prefer to convert the system of linear equations into a matrix equation, and then apply matrix manipulation operations to solve it. This approach is often useful when the system of equations arises as part of a general algorithm, and you do not know in advance how many variables will be involved.

A system of linear equations can be stated in matrix form as m.x==b, where x is the vector of variables.

Note that if your system of equations is sparse, so that most of the entries in the matrix m are zero, then it is best to represent the matrix as a (RefLink[SparseArray, paclet:ref/SparseArray]) object. As discussed in "Sparse Arrays: Linear Algebra", you can convert from symbolic equations to (RefLink[SparseArray, paclet:ref/SparseArray]) objects using (RefLink[CoefficientArrays, paclet:ref/CoefficientArrays]). All the functions described here work on (RefLink[SparseArray, paclet:ref/SparseArray]) objects as well as ordinary matrices.

Solving and analyzing linear systems.

Here is a 2×2 matrix:

m={{1,5},{2,1}}

This gives two linear equations:

m.{x,y}=={a,b}

You can use (RefLink[Solve, paclet:ref/Solve]) directly to solve these equations:

Solve[%,{x,y}]

You can also get the vector of solutions by calling (RefLink[LinearSolve, paclet:ref/LinearSolve]). The result is equivalent to the one you get from (RefLink[Solve, paclet:ref/Solve]):

LinearSolve[m,{a,b}]

Another way to solve the equations is to invert the matrix m, and then multiply {a,b} by the inverse. This is not as efficient as using (RefLink[LinearSolve, paclet:ref/LinearSolve]):

Inverse[m].{a,b}

(RefLink[RowReduce, paclet:ref/RowReduce]) performs a version of Gaussian elimination and can also be used to solve the equations:

RowReduce[{{1,5,a},{2,1,b}}]

If you have a square matrix m with a nonzero determinant, then you can always find a unique solution to the matrix equation m.x==b for any b. If, however, the matrix m has determinant zero, then there may be either no vector, or an infinite number of vectors x which satisfy m.x==b for a particular b. This occurs when the linear equations embodied in m are not independent.

When m has determinant zero, it is nevertheless always possible to find nonzero vectors x that satisfy m.x==0. The set of vectors x satisfying this equation form the null space or kernel of the matrix m. Any of these vectors can be expressed as a linear combination of a particular set of basis vectors, which can be obtained using (RefLink[NullSpace, paclet:ref/NullSpace])[m].

Here is a simple matrix, corresponding to two identical linear equations:

m={{1,2},{1,2}}

The matrix has determinant zero:

Det[m]

(RefLink[LinearSolve, paclet:ref/LinearSolve]) cannot find a solution to the equation m.x==b in this case:

LinearSolve[m,{a,b}]

There is a single basis vector for the null space of m:

NullSpace[m]

Multiplying the basis vector for the null space by m gives the zero vector:

m.%[[1]]

There is only 1 linearly independent row in m:

MatrixRank[m]

(RefLink[NullSpace, paclet:ref/NullSpace]) and (RefLink[MatrixRank, paclet:ref/MatrixRank]) have to determine whether particular combinations of matrix elements are zero. For approximate numerical matrices, the (RefLink[Tolerance, paclet:ref/Tolerance]) option can be used to specify how close to zero is considered good enough. For exact symbolic matrices, you may sometimes need to specify something like (RefLink[ZeroTest, paclet:ref/ZeroTest])->((RefLink[FullSimplify, paclet:ref/FullSimplify])[#]==0&) to force more to be done to test whether symbolic expressions are zero.

Here is a simple symbolic matrix with determinant zero:

m={{a,b,c},{2 a,2 b,2 c},{3 a,3 b,3 c}}

The basis for the null space of m contains two vectors:

NullSpace[m]

Multiplying m by any linear combination of these vectors gives zero:

Simplify[m.(x %[[1]]+y %[[2]])]

An important feature of functions like (RefLink[LinearSolve, paclet:ref/LinearSolve]) and (RefLink[NullSpace, paclet:ref/NullSpace]) is that they work with rectangular, as well as square, matrices.

When you represent a system of linear equations by a matrix equation of the form m.x==b, the number of columns in m gives the number of variables, and the number of rows gives the number of equations. There are a number of cases.

Classes of linear systems represented by rectangular matrices.

This asks for the solution to the inconsistent set of equations x==1 and x==0:

LinearSolve[{{1},{1}},{1,0}]

This matrix represents two equations, for three variables:

m={{1,3,4},{2,1,3}}

(RefLink[LinearSolve, paclet:ref/LinearSolve]) gives one of the possible solutions to this underdetermined set of equations:

v=LinearSolve[m,{1,1}]

When a matrix represents an underdetermined system of equations, the matrix has a nontrivial null space. In this case, the null space is spanned by a single vector:

NullSpace[m]

If you take the solution you get from (RefLink[LinearSolve, paclet:ref/LinearSolve]), and add any linear combination of the basis vectors for the null space, you still get a solution:

m.(v+4 %[[1]])

The number of independent equations is the rank of the matrix (RefLink[MatrixRank, paclet:ref/MatrixRank])[m]. The number of redundant equations is (RefLink[Length, paclet:ref/Length])[(RefLink[NullSpace, paclet:ref/NullSpace])[m]]. Note that the sum of these quantities is always equal to the number of columns in m.

Generating (RefLink[LinearSolveFunction, paclet:ref/LinearSolveFunction]) objects.

In some applications, you will want to solve equations of the form m.x==b many times with the same m, but different b. You can do this efficiently in the Wolfram Language by using (RefLink[LinearSolve, paclet:ref/LinearSolve])[m] to create a single (RefLink[LinearSolveFunction, paclet:ref/LinearSolveFunction]) that you can apply to as many vectors as you want.

This creates a (RefLink[LinearSolveFunction, paclet:ref/LinearSolveFunction]):

f=LinearSolve[{{1,4},{2,3}}]

You can apply this to a vector:

f[{5,7}]

You get the same result by giving the vector as an explicit second argument to (RefLink[LinearSolve, paclet:ref/LinearSolve]):

LinearSolve[{{1,4},{2,3}},{5,7}]

But you can apply f to any vector you want:

f[{-5,9}]

Solving least-squares problems.

This linear system is inconsistent:

LinearSolve[{{1,2},{3,4},{5,6}},{-1,0,2}]

(RefLink[LeastSquares, paclet:ref/LeastSquares]) finds a vector x that minimizes m.x-b in the least-squares sense:

LeastSquares[{{1,2},{3,4},{5,6}},{-1,0,2}]