Methods Linear Systems - Tcirwin PDF
Methods Linear Systems - Tcirwin PDF
Therin Irwin
March 11, 2012
Abstract
Linear systems of equations are notoriously difficult to solve. Most numerical
methods for solving linear systems are plagued by inaccuracy in special cases or
just being too slow. In this report, four methods will be compared in accuracy
when solving this linear system:
1
1
+ =
+ = 2
where is a very small number. The four methods compared are Nave Gaussian
Elimination, the Gauss-Seidel Method, Iterative Refinement, and Scaled Partial
Pivoting. Each of these is plagued by their own problems. Nave Gaussian
Elimination, the standard for hand-solving linear systems, can actually return the
wrong answer in some cases. The Gauss-Seidel method only works when the matrix
representing the linear system is diagonally dominant. Finally, Iterative Refinement
adds extra work onto the already slow Gaussian Elimination process.
In addition, this report will attempt to discover ways to determine if a linear
system is fit to be solved by one of the methods described above.
=
1 1
2
1
=
1
1/
1/
=
1
0 1 1/
2 1/
= 2
1
=
1
1
2
=
1
1
=1
lim
1
1
2
1
=1
lim
(1.1)
1
Therefore, the correct solution to this system is
when is very small. The
1
condition number can tell us how sensitive the solution to this linear system is. If
the condition number is large, the system is very sensitive:
() =
1 1/
1
() =
1 1
1
(1.2)
1
1 = !1 + 1" 1 = 1 + 1
1
(1.3)
1 1/
As we can see, the condition number of the matrix =
Condition Number
10+
{1.0000001, 0.9999999}
10,000,003
10%
10,
10-
10
{1.000001, 0.999999}
{1.00000001, 0.99999999}
{1.000000001, 0.999999999}
{1.0000000001, 0.9999999999}
1,000,003
100,000,003
1,000,000,003
10,000,000,003
So, as gets smaller, we will have a harder time getting an accurate solution for
this matrix.
wrong answer. To determine whether the method will return the wrong answer, we
will use the condition number of the matrix form of a linear system.
Using this method, we can determine at what point does the value of return the
incorrect answer, and what condition number corresponds to this value of .
2.1 Implementation
&
2
0
9
3 7 . 7 = .: 7
6 8
;
For each column of the coefficient matrix, we make every element below the
diagonal zero by using matrix row operations. These row operations are also
multiplied through to the & matrix in = &. For our example matrix, we would end
up with:
/
>
=0
=
=
<0
&
1
2 &
/
4
&
/
9
>
1 A
1 A
=
@
3 0 = : 9@
/ @ . 7 =
/ @
4 @ 8
4 @
=
6 0?
<; / 9?
/
0
1
1
3 0
: 9
/
/
4 C
4 C
8 = B
6 0
; 9
/
/
Fig. 2.1:
Determining when F produces an incorrect result.
So, the last value of for which the solution is correct is 10G . It is quite easy to
see from Fig. 2.1 that when the condition number becomes too large to be
accurately represented, the answer becomes wrong.
In terms of our symbolic calculation (formula 1.1) earlier, this also makes sense.
The algorithm first solves the equation for and then works backwards to . In
solving for , the algorithm now finds that the solution is exactly one. Plugging 1
into the equation for gets you:
=
11 0
= =0
So the answer for is now calculated as zero. For larger values of , 1 would
have resulted in a very small number. This very small number divided by (an
equally small number) produced a result of exactly one.
When implemented and tested using the linear system , the check perfectly
indicated when an inaccuracy occurred:
P = ^ &
This will return an P which is close to zero if the answer ^ is nearly correct. This
test was also performed on several different matrices and performed equally well
as the previous test.
It is worth noting that this test would take slightly longer than the previous. The
difference in computational complexity would be trivial, however, compared to the
time it takes to compute the answer using Gaussian Elimination.
3 Iterative Refinement
Iterative Refinement is a very easily implemented algorithm that is able to
overcome most of the error involved in solving linear systems with Gaussian
Elimination. An Iterative Refinement algorithm generally uses Gaussian Elimination
as its first step to get a solution that is in the ballpark.
3.1 Implementation
Starting with a (possibly) incorrect answer from Gaussian Elimination (call it our
initial guess), Iterative Refinement attempts on each iteration to solve the system
using the previous guess, and then uses that answer as a basis for a correction.
Assume is the matrix form of the linear system, and & is the right-hand side of
the linear system. For each iteration N of the algorithm, the following happens:
P_ = & _
The algorithm continues until the desired accuracy is achieved. The stopping
criteria for this algorithm are very similar to that of Newtons Iteration, where the
previous correction is compared to the current correction, and the iteration stops
if the comparison is within some margin of error.
4.1 Implementation
Implementing Scaled Partial Pivoting is similar to Gaussian Elimination, except that
for Scaled Partial Pivoting a choice must be made about which row to use as the
pivot row. (In Nave Gaussian Elimination, we just choose the top row to be the
pivot row). To do this, we first find the largest element in magnitude of each row
of the matrix and store it in an array, call it the scale array. These are the elements
we use to determine which pivot is the largest relative to the other elements in its
row.
Next, we begin the Gaussian Elimination algorithm as usual, but instead of
choosing the top row as the pivot, we instead search through the first column to
find the largest relative pivot value:
max
JcIc_
d/IJ d
`0/;2[6]
Here, N is the number of equations in the system, and 9 is the submatrix we are
working in. Once the best pivot value is found, the best row is swapped so that it is
at the top of the current submatrix. After this occurs, the Gaussian Elimination
algorithm continues as normal.
It is time-consuming to actually swap rows of a matrix, especially in the case of a
large matrix. Therefore, a row index array is used to represent the swapping of
rows. At the beginning of the algorithm, this array, call it rowSwap, is initialized to
contain [0, 1, 2, , N]. This represents the fact that no rows have been swapped yet,
so the 0th row corresponds to the 0th stored row. But if we were to swap rows 4 and
0, PEhih/j would contain [4, 1, 2, 3, 0, , n], indicating that the 0th row is now located
at the 4th storage position.
5 Gauss-Seidel Method
The Gauss-Seidel Method is an iterative method that uses previously computed
values of the vector to approach a better solution. The initial guess is generally
not a problem for this method and is usually set to the zero vector. This method is
certainly the fastest of those discussed, but it does not converge for all matrices.
5.1 Implementation
This method is fairly easy to implement compared to the others. One would start
with a column vector = [0, 0, ,0]l as the initial guess to the system. Then the
/IJ (m)
/IJ (m) &I
= q r ! " J r ! " J
+ v
/II
/II
/II
JstI
JuI
6 Comparison of Methods
Each of the methods examined have their own unique issues.
As shown in Fig. 6.1, Iterative Refinement takes significantly longer than Scaled
Partial Pivoting.
Accuracy of Implementations. Both Iterative Refinement and Scaled Partial
Pivoting provide reasonably accurate solutions. Iterative Refinement can obviously
be as accurate as the computer system allows by simply doing more iterations. For
Scaled Partial Pivoting, however, we do not have this option, so this
implementation tends to be slightly less accurate.
Scaled Partial Pivoting does not guarantee accuracy for all matrices. In
implementing such an algorithm, one would have to take this into account.
Fortunately, Scaled Partial Pivoting is adequate for most linear systems.
Fig. 6.2 shows the solutions for Iterative Refinement and Scaled Partial Pivoting for
values of < 10%
-6 : ----------------------------Scaled Partial Pivoting:
Answer: [1.000001000001, 0.999998999999]
Iterative Refinement:
Answer: [1.000001000001, 0.999998999999]
-7 : ----------------------------Scaled Partial Pivoting:
Answer: [1.00000010000001, 0.99999989999999]
Iterative Refinement:
Answer: [1.00000010000001, 0.99999989999999]
-8 : ----------------------------Scaled Partial Pivoting:
Answer: [1.00000001, 0.99999999]
Iterative Refinement:
Answer: [1.0000000100000002, 0.9999999899999998]
-9 : -----------------------------
Unfortunately, this method did not converge for the matrix discussed in Section
1. This is because the Gauss-Seidel method is only guaranteed to converge for
diagonally dominant or symmetric positive definite matrices.
Therefore, unless the linear system being solved is guaranteed to be positive
definite or diagonally dominant, Gauss-Seidel should not be used.
7 Conclusion
Based on the results reported above, if we were looking to solve a very illconditioned linear system, we would use either the Scaled Partial Pivoting or the
Gauss-Seidel method. If the matrix representing the linear system is guaranteed to
converge for the Gauss-Seidel method, then this would be the method to use as it
is much faster than Scaled Partial Pivoting.
As stated above, however, Scaled Partial Pivoting does not necessarily produce the
correct answer for all matrices, so it is still beneficial to use the inaccuracy checks
described in Section 2.2 to make sure the method is returning the correct answer.
C:\Users\Therin\workspace\EigenFinder\src\GaussianElimination.java
import java.util.Arrays;
import java.util.Scanner;
public class GaussianElimination {
public static MatrixOps.Answer solve(double[][] mx, double[] vx) {
boolean inacc = false;
MatrixOps.Answer a = new MatrixOps.Answer();
a.ans = new double[vx.length];
double[][] m = new double[mx.length][];
double[] v = new double[vx.length];
MatrixOps.array2DCopy(mx, m);
System.arraycopy(vx, 0, v, 0, vx.length);
// Reduce the Matrix.
for (int i = 0; i < m[0].length; i++) {
double pivot = m[i][i];
// Check if pivot value is 1, if not, divide row by pivot.
if (pivot != 1) {
MatrixOps.rowDiv(m, i, pivot);
v[i] /= pivot;
}
// Zero all values below the pivot.
for (int j = i + 1; j < m[0].length; j++) {
double fix = m[j][i];
if (fix == 0)
continue;
MatrixOps.rowMultSub(m, i, j, fix);
v[j] -= v[i] * fix;
}
}
// Compute the x vector.
for (int i = m[0].length - 1; i >= 0; i--) {
double subAns = v[i];
for (int j = i + 1; j < m[0].length; j++) {
// Check if the solution will be inaccurate.
inacc = inacc ||
(2 + m[i][j] == 1 + m[i][j] || 1 + m[i][j] == 1);
subAns -= m[i][j] * a.ans[j];
a.mults++;
}
a.ans[i] = subAns;
}
-1-
C:\Users\Therin\workspace\EigenFinder\src\GaussianElimination.java
-2-
C:\Users\Therin\workspace\EigenFinder\src\GaussianElimination.java
-3-
C:\Users\Therin\workspace\EigenFinder\src\MatrixOps.java
C:\Users\Therin\workspace\EigenFinder\src\MatrixOps.java
-2-
C:\Users\Therin\workspace\EigenFinder\src\ScaledPartialPivoting.java
-1-
C:\Users\Therin\workspace\EigenFinder\src\ScaledPartialPivoting.java
-2-
C:\Users\Therin\workspace\EigenFinder\src\GaussSeidel.java
= 0; j < i; j++)
+= mx[i][j] * xAns[j];
= i + 1; j < vx.length; j++)
+= mx[i][j] * xPrevAns[j];
-1-