5. Gaussian elimination

The GaussianElimination example solution is fairly complicated, partly because Gaussian elimination is complicated, but also because it must convert user-entered text into an augmented matrix.

The program uses the following code to build the augmented matrix from the user's text. It gets the equations' coefficients from the coefficientsTextBox control. It gets the equations' results (the Cs on the right in the problem description) from the valuesTextBox control:

// Load the augmented array.
// Column numCols holds the result values.
// Column numCols + 1 will hold the final values after
// backsolving.
private double[,] LoadArray(out int numRows, out int numCols)
{
// Build the augmented matrix.
string[] valueRows = valuesTextBox.Text.Split(
new string[] { " " },
StringSplitOptions.RemoveEmptyEntries);
string[] coefRows = coefficientsTextBox.Text.Split(
new string[] { " " },
StringSplitOptions.RemoveEmptyEntries);
string[] oneRow = coefRows[0].Split(
new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
numRows = coefRows.GetUpperBound(0) + 1;
numCols = oneRow.GetUpperBound(0) + 1;
double[,] arr = new double[numRows, numCols + 2];
for (int r = 0; r < numRows; r++)
{
oneRow = coefRows[r].Split(
new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int c = 0; c < numCols; c++)
{
arr[r, c] = double.Parse(oneRow[c]);
}
arr[r, numCols] = double.Parse(valueRows[r]);
}

return arr;
}

This method gets the multiline string of values in valuesTextBox, splits the entries delimited by the carriage return/line feed combination, removes any empty entries, and saves the values in the valueRows array. It then uses a similar technique to load the rows of coefficients into the coefRows array. The method then splits the first row of coefficients delimited by spaces to save that row's coefficients in the oneRow array.

The code uses the length of the coefRows array to get the number of rows. It uses the length of the oneRow array to get the number of columns. Note that the number of columns includes only the equations' coefficients; it does not include the value column or the final result column in the augmented array.

After it knows the numbers of rows and columns, the code creates the arr array to hold the augmented matrix. It loops through the values to fill in the array and returns it.

The following GaussianEliminate method solves an augmented matrix:

// Perform Gaussian elimination.
// Note that arr should be the augmented array.
// Initially the second-to-last column should hold the result values.
// In the end, the final column will hold the final values after
backsolving.
private void GaussianEliminate(double[,] arr)
{
const double tiny = 0.00001;

// Get the number of rows and columns.
int numRows = arr.GetUpperBound(0) + 1;
int numCols = arr.GetUpperBound(1) - 1;

// Start solving.
for (int r = 0; r < numRows - 1; r++)
{
// Zero out all entries in column r after this row.
// See if this row has a non-zero entry in column r.
if (Math.Abs(arr[r, r]) < tiny)
{
// Too close to zero. Try to swap with a later row.
for (int r2 = r + 1; r2 < numRows; r2++)
{
if (Math.Abs(arr[r2, r]) > tiny)
{
// This row will work. Swap them.
for (int c = 0; c <= numCols; c++)
{
double tmp = arr[r, c];
arr[r, c] = arr[r2, c];
arr[r2, c] = tmp;
}
break;
}
}
}

// If this row has a non-zero entry in column r, use it.
if (Math.Abs(arr[r, r]) > tiny)
{
// Zero out this column in later rows.
for (int r2 = r + 1; r2 < numRows; r2++)
{
double factor = -arr[r2, r] / arr[r, r];
for (int c = r; c <= numCols; c++)
{
arr[r2, c] = arr[r2, c] + factor * arr[r, c];
}
}
}
}

// Display the upper-triangular array. (For debugging.)
PrintArray(arr);

// See if we have a solution.
if (arr[numRows - 1, numCols - 1] == 0)
{
// We have no solution.
// If all entries in this row are 0, then there is no solution.
// Otherwise the solution is not unique.
for (int c = 0; c <= numCols + 1; c++)
if (arr[numRows - 1, c] != 0)
throw new Exception("There is no solution");
throw new Exception("The solution is not unique");
}

// We have a solution. Backsolve.
for (int r = numRows - 1; r >= 0; r--)
{
double tmp = arr[r, numCols];
for (int r2 = r + 1; r2 < numRows; r2++)
{
tmp -= arr[r, r2] * arr[r2, numCols + 1];
}
arr[r, numCols + 1] = tmp / arr[r, r];
}
}

This method first gets the number of rows and columns. Note that the numColumns value does not include the augmented matrix's last two columns, which hold the equations' values and the final results.

The method then loops through the rows, using the r row to zero out the r column values in the following rows. Before it uses the r row, the program verifies that it has a non-zero entry in the column r. If the row has a zero in that position, the code swaps it with a later row that has a non-zero entry in that column.

Notice has a zero in that position really means has a small value that could cause overflow when used as a denominator. It is important to check that floating point numbers are not too small before you divide by them.

After it has finished converting the matrix into upper-triangular form, the code calls the PrintArray method to display the array's values in the Console window. That method is straightforward, so I won't include it here. Download the example solution to see the details.

Next, the code checks the final row to see if it has a non-zero entry in its final coefficient column. If that entry is zero, then there is no solution for the original set of equations and the method throws an exception.

If the final row has a non-zero entry for its final coefficient, the method backsolves to find the final solution.

The result is passed back to the calling code through the modified array.

The following code shows how the program uses the GaussianEliminate method when you click the program's Solve button:

// Solve the system of equations.
private void solveButton_Click(object sender, EventArgs e)
{
// Build the augmented matrix.
// The values numRows and numCols are the number of rows
// and columns in the matrix, not the augmented matrix.
int numRows, numCols;
double[,] arr = LoadArray(out numRows, out numCols);
double[,] origArr = LoadArray(out numRows, out numCols);

// Display the initial arrays.
PrintArray(arr);
PrintArray(origArr);

// Perform Gaussian elimination.
try
{
GaussianEliminate(arr);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

// Display the modified array in the Console window.
PrintArray(arr);

// Display the results on the form.
StringBuilder sb = new StringBuilder();
sb.AppendLine(" Values");
for (int r = 0; r < numRows; r++)
{
sb.AppendLine("x" + r.ToString() + " = " +
arr[r, numCols + 1].ToString());
}

// Verify.
sb.AppendLine();
sb.AppendLine(" Check:");
for (int r = 0; r < numRows; r++)
{
double tmp = 0;
for (int c = 0; c < numCols; c++)
tmp += origArr[r, c] * arr[c, numCols + 1];
sb.AppendLine(tmp.ToString());
}
resultsTextBox.Text = sb.ToString();
}

The code first calls the LoadArray method to load the values entered by the user. It calls the method twice to make two copies of the array. It will use one for Gaussian elimination and it will save the other so it can later check the results to verify that the solution works.

The code calls the PrintArray method to display the initial augmented matrix and then calls GaussianEliminate to solve the system of equations.

After the GaussianEliminate method returns, the code calls PrintArray again to display the finished augmented matrix. It then uses StringBuilder to make a string showing the solution.

The method then multiples the original matrix's entries by the solution values to verify that the solution is correct. It adds the results to StringBuilder and finally displays the result.

The following table shows the solutions to the systems of equations mentioned in the problem description:

System of Equations

Solution

{3, -1, -2}

{-0.2, 4, -0.8}

{7.87, -82.75, 302.17, -446.75, 220.47}

Has no solution

Has no unique solution

 

Download the GaussianElimination example solution to see additional details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.185.196