I made a program today that performs gauss-jordan elimination on a matrix.
Code:
I decided to make it print the entire matrix after each step, which sometimes leads to the same matrix being printed two or more times in a row in the event that it performs a check that doesn't result in the matrix being modified, but still prints after the check. Here is a sample of the output it produces:
Code:
There may still be mistakes in there, but it has worked on all the funky cases I could think of
Basically, the program asks the user to input the size of the matrix, then the contents, and stores that to a 2d array. Then it recursively puts leading 1s and clears under them by subtracting multiples of the row that just got a leading 1, to make a diagonal line through the matrix. The recursion is done by incrementing the k variable which serves as an offset for the row and column. Then there is a routine (checkAndFixLeadingOnes()) that checks that all rows have leading 1s and divides the ones that don't in order to account for the fact that some matrices may not have unique solutions, so a perfect diagonal line won't work in those cases. At this point, we have a matrix in row-echelon form. Then the jordan() method recursively (this time with the m and n variables) checks above the leading 1s, and subtracts multiples of the rows from bottom to top to clear above the leading 1s. And then the matrix is in reduced row-echelon form! Along the way, the entire matrix gets rounded once in an attempt to reduce the amount of error that gets put into matrix as these operations take place. Of course, this rounding will help the accuracy if the final matrix should have whole numbers, and will hinder the accuracy if the final matrix should have fractional numbers, but I figured textbook problems often have nice integer solutions, so the rounding would help overall. #RuleUtilitarianism?
Code:
package matrices;
import javax.swing.JOptionPane;
class matrix {
private final int rows;
private final int columns;
private double[][] arr;
private int k = -1;
matrix(int r, int c, double[][] a) {
rows = r;
columns = c;
arr = a;
}
public void printMatrix() {
System.out.println();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
public double[][] putAOne() {
k++;
double temp = arr[k][k];
if (temp < -1.0E-12 || temp > 1.0E-12) {
for (int i = k; i < columns; i++) {
arr[k][i] = arr[k][i] / temp;
}
printMatrix();
}
return arr;
}
public double[][] emptyUnderOne() {
for (int i = k + 1; i < rows; i++) {
double temp = arr[i][k];
for (int j = 0; j < columns; j++) {
arr[i][j] = arr[i][j] - temp * arr[k][j];
}
}
printMatrix();
return arr;
}
public double[][] roundMatrix() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
arr[i][j] = Math.round(arr[i][j] * 1.0E12) / 1.0E12;
}
}
printMatrix();
return arr;
}
public double[][] checkAndFixLeadingOnes() {
double temp;
for (int i = 0; i < rows; i++) {
boolean goodRow = false;
double accumulator = 0.0;
int pos = 0;
for (int j = 0; j < columns && goodRow == false; j++) {
accumulator += arr[i][j];
if (accumulator == 1.0) {
goodRow = true;
} else {
if (accumulator != 0.0 && pos == 0) {
pos = j;
}
}
}
if (goodRow == false && accumulator != 0.0) {
temp = arr[i][pos];
for (int j = 0; j < columns; j++) {
arr[i][j] = arr[i][j] / temp;
}
}
}
printMatrix();
return arr;
}
public double[][] jordan() {
for (int i = (rows - 1); i >= 0; i--) {
int pos = -1;
double accumulator = 0.0;
for (int j = 0; j < columns; j++) {
accumulator += arr[i][j];
if (accumulator == 1.0 && pos == -1) {
pos = j;
}
if (accumulator > 1.0E-12 || accumulator < -1.0E-12) {
for (int m = (i - 1); m >= 0; m--) {
if (arr[m][pos] > 1.0E-12 || arr[m][pos] < -1.0E-12) {
double temp = arr[m][pos];
for (int n = 0; n < columns; n++) {
arr[m][n] -= temp * arr[i][n];
}
}
}
}
}
}
printMatrix();
return arr;
}
}
public class Matrices {
public static void main(String[] args) {
String row = JOptionPane.showInputDialog("Enter the number of rows in the matrix");
int rows = Integer.parseInt(row);
while (rows < 1) {
row = JOptionPane.showInputDialog("There must be at least 1 row.");
rows = Integer.parseInt(row);
}
String column = JOptionPane.showInputDialog("Enter the number of columns in the matrix");
int columns = Integer.parseInt(column);
while (columns < 2) {
column = JOptionPane.showInputDialog("There must be at least 2 columns");
columns = Integer.parseInt(column);
}
String value;
double[][] arr = new double[rows][columns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
value = JOptionPane.showInputDialog("Enter the value in row " + (i + 1) + ", and in column " + (j + 1));
arr[i][j] = Double.parseDouble(value);
}
}
matrix matrix1 = new matrix(rows, columns, arr);
matrix1.printMatrix();
for (int a = 1; a <= rows; a++) {
matrix1.putAOne();
if (a != rows) {
matrix1.emptyUnderOne();
}
}
matrix1.roundMatrix();
matrix1.checkAndFixLeadingOnes();
System.out.println("REF");
matrix1.jordan();
System.out.println("RREF");
}
}
I decided to make it print the entire matrix after each step, which sometimes leads to the same matrix being printed two or more times in a row in the event that it performs a check that doesn't result in the matrix being modified, but still prints after the check. Here is a sample of the output it produces:
Code:
1.0 -1.0 -3.0 1.0
3.0 -2.0 -4.0 6.0
3.0 0.0 6.0 12.0
1.0 -1.0 -3.0 1.0
3.0 -2.0 -4.0 6.0
3.0 0.0 6.0 12.0
1.0 -1.0 -3.0 1.0
0.0 1.0 5.0 3.0
0.0 3.0 15.0 9.0
1.0 -1.0 -3.0 1.0
0.0 1.0 5.0 3.0
0.0 3.0 15.0 9.0
1.0 -1.0 -3.0 1.0
0.0 1.0 5.0 3.0
0.0 0.0 0.0 0.0
1.0 -1.0 -3.0 1.0
0.0 1.0 5.0 3.0
0.0 0.0 0.0 0.0
1.0 -1.0 -3.0 1.0
0.0 1.0 5.0 3.0
0.0 0.0 0.0 0.0
REF
1.0 0.0 2.0 4.0
0.0 1.0 5.0 3.0
0.0 0.0 0.0 0.0
RREF
There may still be mistakes in there, but it has worked on all the funky cases I could think of
Basically, the program asks the user to input the size of the matrix, then the contents, and stores that to a 2d array. Then it recursively puts leading 1s and clears under them by subtracting multiples of the row that just got a leading 1, to make a diagonal line through the matrix. The recursion is done by incrementing the k variable which serves as an offset for the row and column. Then there is a routine (checkAndFixLeadingOnes()) that checks that all rows have leading 1s and divides the ones that don't in order to account for the fact that some matrices may not have unique solutions, so a perfect diagonal line won't work in those cases. At this point, we have a matrix in row-echelon form. Then the jordan() method recursively (this time with the m and n variables) checks above the leading 1s, and subtracts multiples of the rows from bottom to top to clear above the leading 1s. And then the matrix is in reduced row-echelon form! Along the way, the entire matrix gets rounded once in an attempt to reduce the amount of error that gets put into matrix as these operations take place. Of course, this rounding will help the accuracy if the final matrix should have whole numbers, and will hinder the accuracy if the final matrix should have fractional numbers, but I figured textbook problems often have nice integer solutions, so the rounding would help overall. #RuleUtilitarianism?