From ccb9e31d8d63e2e415898eed19497f6060b7f307 Mon Sep 17 00:00:00 2001 From: Nail Iskhakov Date: Wed, 30 Jan 2019 05:42:25 +0300 Subject: [PATCH 1/3] Structure and main classes added --- .idea/misc.xml | 2 +- .idea/project.iml | 9 ++++ in.txt | 4 ++ src/solver/AugmentedMatrix.java | 70 +++++++++++++++++++++++++ src/solver/LinearEquationSolver.java | 40 +++++++++++++++ src/solver/Main.java | 76 +++++++++++++++++++++++++++- src/solver/Row.java | 53 +++++++++++++++++++ 7 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 in.txt create mode 100644 src/solver/AugmentedMatrix.java create mode 100644 src/solver/LinearEquationSolver.java create mode 100644 src/solver/Row.java diff --git a/.idea/misc.xml b/.idea/misc.xml index a165cb3..cbb200f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/project.iml b/.idea/project.iml index 47baa8c..d34aa22 100644 --- a/.idea/project.iml +++ b/.idea/project.iml @@ -6,5 +6,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/in.txt b/in.txt new file mode 100644 index 0000000..b0bf574 --- /dev/null +++ b/in.txt @@ -0,0 +1,4 @@ +3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 \ No newline at end of file diff --git a/src/solver/AugmentedMatrix.java b/src/solver/AugmentedMatrix.java new file mode 100644 index 0000000..87cf1ad --- /dev/null +++ b/src/solver/AugmentedMatrix.java @@ -0,0 +1,70 @@ +package solver; + +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.Scanner; + +public class AugmentedMatrix { + private Row[] matrix; + + AugmentedMatrix(double[][] matrix) { + setMatrix(matrix); + } + + AugmentedMatrix() {} + + void readMatrix(Scanner scanner) throws InputMismatchException { + int n = scanner.nextInt(); + int m = n+1; + matrix = new Row[n]; + for (int i = 0; i < n; i++) { + matrix[i] = new Row(m); + for (int j = 0; j < m; j++) { + this.set(i, j, scanner.nextDouble()); + } + } + } + + void set(int i, int j, double value) { + matrix[i].set(j, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < matrix.length; i++) { + sb.append(Arrays.toString(matrix[i].getRow())); + sb.append("\n"); + } + return sb.toString(); + } + + + public double[][] getMatrix() { + double[][] copy = new double[matrix.length][]; + for(int i = 0; i < matrix.length; i++) { + copy[i] = matrix[i].getRow(); + } + return copy; + } + + public void setMatrix(double[][] matrix) { + this.matrix = new Row[matrix.length]; + for(int i = 0; i < matrix.length; i++) { + this.matrix[i] = new Row(matrix[i]); + } + } + + public Row getRow(int index) { + return this.matrix[index]; + } + + public int[] size() { + int[] size = new int[2]; + size[0] = matrix.length; + size[1] = matrix[0].size(); + return size; + } + + +} diff --git a/src/solver/LinearEquationSolver.java b/src/solver/LinearEquationSolver.java new file mode 100644 index 0000000..7f42326 --- /dev/null +++ b/src/solver/LinearEquationSolver.java @@ -0,0 +1,40 @@ +package solver; + +public class LinearEquationSolver { + AugmentedMatrix matrix; + + LinearEquationSolver(AugmentedMatrix matrix) { + this.matrix = new AugmentedMatrix(matrix.getMatrix()); + } + + public void transformToUpperTriangularForm() { + Row currentRow; + int n = matrix.size()[0]; + for(int i = 0; i < n; i++) { + currentRow = matrix.getRow(i).normalizeRow(i); + for(int j = i + 1; j < n; j++) { + matrix.getRow(j).normalizeRow(i).subtract(currentRow); + } + } + } + + public void transformToLowerTriangularForm() { + Row currentRow; + int n = matrix.size()[0]; + for(int i = n-1; i >= 0; i--) { + currentRow = matrix.getRow(i).normalizeRow(i); + for(int j = i-1; j >= 0; j--) { + matrix.getRow(j).normalizeRow(i).subtract(currentRow); + } + } + } + + public void tranformToNormalizedDiagonalForm() { + transformToUpperTriangularForm(); + transformToLowerTriangularForm(); + } + + public AugmentedMatrix getMatrix() { + return matrix; + } +} diff --git a/src/solver/Main.java b/src/solver/Main.java index 4404714..24da4c5 100644 --- a/src/solver/Main.java +++ b/src/solver/Main.java @@ -1,7 +1,81 @@ package solver; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.InputMismatchException; +import java.util.Scanner; + public class Main { + static String showHelp() { + String helpMsg = "This program is intended to solve Linear Equations with any amount of variables. \n\n" + + "Options: " + + "\n\t * -in [pathToFile] reads file with matrix coefficients and constant column of numbers " + + "\n\t * -out [pathToFile] writes results to the output file " + + "\n\t * -h shows help information " + + "\n\nExample: \njava Solver -in in.txt -out out.txt"; + return helpMsg; + } + public static void main(String[] args) { - System.out.print("Hello world!"); + // Getting and handling console parameters + String inputFile=""; + String outputFile=""; + for(int i = 0; i < args.length; i++) { + try { + switch (args[i]) { + case "-in": + inputFile = args[i + 1]; + break; + case "-out": + outputFile = args[i + 1]; + break; + case "-h" : + System.out.println(showHelp()); + return; + + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("Invalid command line options, use '-h' option to see help"); + return; + } + } + + if(inputFile.isEmpty() || outputFile.isEmpty()) { + System.err.println("Invalid command line options, use '-h' option to see help"); + return; + } + + System.out.println("Input File: " + inputFile + "\nOutput File: " + outputFile); + + // Working with input file + File file = new File(inputFile); + AugmentedMatrix matrix = new AugmentedMatrix(); + try { + Scanner fileScanner = new Scanner(file); + matrix.readMatrix(fileScanner); + } catch(FileNotFoundException e) { + System.out.println("File: " + file.getAbsolutePath() + " doesn't exist"); + return; + } catch (InputMismatchException e) { + System.err.println("Invalid structure of input file: " + file.getAbsolutePath()); + return; + } + + System.out.println(matrix); + +// for(int i = 0; i < matrix.size()[0]; i++) { +// matrix.getRow(i).normalizeRow(0); +// } +// +// matrix.getRow(1).subtract(matrix.getRow(0)); +// matrix.getRow(2).subtract(matrix.getRow(0)); + + LinearEquationSolver solver = new LinearEquationSolver(matrix); + solver.transformToUpperTriangularForm(); + solver.transformToLowerTriangularForm(); + + System.out.println(); + System.out.println(solver.getMatrix()); + } } \ No newline at end of file diff --git a/src/solver/Row.java b/src/solver/Row.java new file mode 100644 index 0000000..537a55b --- /dev/null +++ b/src/solver/Row.java @@ -0,0 +1,53 @@ +package solver; + +import java.util.Arrays; + +public class Row { + private double[] row; + + Row(double[] row) { + setRow(row); + } + + Row(int m) { + row = new double[m]; + } + + Row normalizeRow(int index) { + return divide(row[index]); + } + + Row divide(double v) { + for(int i = 0; i < row.length; i++) { + row[i] = row[i] / v; + } + return this; + } + + Row subtract(Row row) { + for(int i = 0; i < this.row.length; i++) { + this.row[i] = this.row[i] - row.get(i); + } + return this; + } + + public double[] getRow() { + return Arrays.copyOf(row, row.length); + } + + public void setRow(double[] row) { + this.row = Arrays.copyOf(row, row.length); + } + + public void set(int j, double value) { + this.row[j] = value; + } + + public double get(int j) { + return this.row[j]; + } + + public int size() { + return this.row.length; + } +} From f49d2613bb9a50e7903e7fa401343d6631ea82cc Mon Sep 17 00:00:00 2001 From: Nail Iskhakov Date: Thu, 31 Jan 2019 05:32:14 +0300 Subject: [PATCH 2/3] Gauss-Jordan Elimination method implemented --- out.txt | 3 + src/solver/AugmentedMatrix.java | 4 ++ src/solver/LinearEquationSolver.java | 90 +++++++++++++++++++++++++--- src/solver/Main.java | 51 ++++++++++------ src/solver/Row.java | 11 +++- 5 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 out.txt diff --git a/out.txt b/out.txt new file mode 100644 index 0000000..5f5fbe7 --- /dev/null +++ b/out.txt @@ -0,0 +1,3 @@ +1 +2 +3 \ No newline at end of file diff --git a/src/solver/AugmentedMatrix.java b/src/solver/AugmentedMatrix.java index 87cf1ad..5c8b6e7 100644 --- a/src/solver/AugmentedMatrix.java +++ b/src/solver/AugmentedMatrix.java @@ -29,6 +29,10 @@ void set(int i, int j, double value) { matrix[i].set(j, value); } + double get(int i, int j) { + return matrix[i].get(j); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/src/solver/LinearEquationSolver.java b/src/solver/LinearEquationSolver.java index 7f42326..e1996b1 100644 --- a/src/solver/LinearEquationSolver.java +++ b/src/solver/LinearEquationSolver.java @@ -1,39 +1,115 @@ package solver; +import java.text.DecimalFormat; + public class LinearEquationSolver { AugmentedMatrix matrix; + StringBuilder logs; + double[] result; LinearEquationSolver(AugmentedMatrix matrix) { this.matrix = new AugmentedMatrix(matrix.getMatrix()); + this.logs = new StringBuilder(); } - public void transformToUpperTriangularForm() { + private void transformToUpperTriangularForm() { Row currentRow; int n = matrix.size()[0]; + double coefficient; for(int i = 0; i < n; i++) { - currentRow = matrix.getRow(i).normalizeRow(i); + currentRow = matrix.getRow(i); + normalizeRowsForTransforming(i, currentRow); for(int j = i + 1; j < n; j++) { - matrix.getRow(j).normalizeRow(i).subtract(currentRow); + subtractRowsForTransforming(i,j,currentRow); } } } - public void transformToLowerTriangularForm() { + private void transformToLowerTriangularForm() { Row currentRow; int n = matrix.size()[0]; + double coefficient; for(int i = n-1; i >= 0; i--) { - currentRow = matrix.getRow(i).normalizeRow(i); + currentRow = matrix.getRow(i); + normalizeRowsForTransforming(i, currentRow); for(int j = i-1; j >= 0; j--) { - matrix.getRow(j).normalizeRow(i).subtract(currentRow); + subtractRowsForTransforming(i,j,currentRow); } } } - public void tranformToNormalizedDiagonalForm() { + private void tranformToDiagonalForm() { transformToUpperTriangularForm(); transformToLowerTriangularForm(); } + private void logMessage(String msg) { + logs.append(msg); + logs.append("\n"); + } + + /** + * Devide every element of matrix[j] row by the element at position i and subtracts currentRow from matrix[j] + * (was originally created to move duplicating code from methods) + * @param i + * @param j + * @param currentRow + */ + private void subtractRowsForTransforming(int i, int j, Row currentRow) { + double coefficient = matrix.getRow(j).get(i); + if(coefficient != 1.0) { + matrix.getRow(j).normalizeRow(i); + logMessage(String.format("R%d / %s - R%d -> R%d", j, new DecimalFormat("#.###").format(coefficient), i, j)); + } else { + logMessage(String.format("R%d - R%d -> R%d", j, i, j)); + } + matrix.getRow(j).subtract(currentRow); + } + + /** + * Divide every element of the row by the element at position `i` and logs results + * (was originally created to move duplicating code from methods) + * @param i index of the element at the row + * @param currentRow + */ + private void normalizeRowsForTransforming(int i, Row currentRow) { + double coefficient = currentRow.get(i); + if(coefficient != 1.0) { + currentRow.normalizeRow(i); + logMessage(String.format("R%d / %s -> R%d", i, new DecimalFormat("#.###").format(coefficient), i)); + } + } + + String getLogs() { + return this.logs.toString(); + } + + double[] getResult() { + return result; + } + + String getResultString() { + StringBuilder sb = new StringBuilder(); + for(double coefficient: result) { + sb.append(new DecimalFormat("#.####").format(coefficient)); + sb.append("\n"); + } + sb.deleteCharAt(sb.length()-1); + return sb.toString(); + } + + LinearEquationSolver solve() { + tranformToDiagonalForm(); + // Get coefficients of the last column + int n = this.matrix.size()[0]; + int m = this.matrix.size()[1]; + result = new double[n]; + for(int i = 0; i < n; i++) { + result[i] = matrix.get(i, m-1); + } + return this; + } + public AugmentedMatrix getMatrix() { return matrix; } diff --git a/src/solver/Main.java b/src/solver/Main.java index 24da4c5..f8c115c 100644 --- a/src/solver/Main.java +++ b/src/solver/Main.java @@ -2,20 +2,33 @@ import java.io.File; import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; import java.util.InputMismatchException; import java.util.Scanner; public class Main { - static String showHelp() { - String helpMsg = "This program is intended to solve Linear Equations with any amount of variables. \n\n" + + + static String getHelp() { + String helpMsg = "This program is intended to solve Linear Equations with any amount of variables using Gauss-Jordan Elimination. \n\n" + "Options: " + - "\n\t * -in [pathToFile] reads file with matrix coefficients and constant column of numbers " + + "\n\t * -in [pathToFile] reads file with the first number - number of equations and variables, and augmented matrix of linear equation" + "\n\t * -out [pathToFile] writes results to the output file " + "\n\t * -h shows help information " + - "\n\nExample: \njava Solver -in in.txt -out out.txt"; + "\n\nExample: \njava Solver -in in.txt -out out.txt" + + "\n\nExample of in.txt:\n" + + "3\n" + + "1 1 2 9\n" + + "2 4 -3 1\n" + + "3 6 -5 0"; return helpMsg; } + /** + * Program should start with necessary options -in [pathToFileWithMatrix] and -out [pathToOutputFile] + * Example: > java Solver -in in.txt -out out.txt + * @param args + */ public static void main(String[] args) { // Getting and handling console parameters String inputFile=""; @@ -30,7 +43,7 @@ public static void main(String[] args) { outputFile = args[i + 1]; break; case "-h" : - System.out.println(showHelp()); + System.out.println(getHelp()); return; } @@ -50,8 +63,7 @@ public static void main(String[] args) { // Working with input file File file = new File(inputFile); AugmentedMatrix matrix = new AugmentedMatrix(); - try { - Scanner fileScanner = new Scanner(file); + try(Scanner fileScanner = new Scanner(file);) { matrix.readMatrix(fileScanner); } catch(FileNotFoundException e) { System.out.println("File: " + file.getAbsolutePath() + " doesn't exist"); @@ -61,21 +73,26 @@ public static void main(String[] args) { return; } + // Input matrix output + System.out.println("Input matrix:"); System.out.println(matrix); -// for(int i = 0; i < matrix.size()[0]; i++) { -// matrix.getRow(i).normalizeRow(0); -// } -// -// matrix.getRow(1).subtract(matrix.getRow(0)); -// matrix.getRow(2).subtract(matrix.getRow(0)); + // Solving equation + System.out.println("Start solving linear equation."); LinearEquationSolver solver = new LinearEquationSolver(matrix); - solver.transformToUpperTriangularForm(); - solver.transformToLowerTriangularForm(); + String res = solver.solve().getResultString(); + System.out.println("Rows manipulation:"); + System.out.println(solver.getLogs()); - System.out.println(); - System.out.println(solver.getMatrix()); + System.out.println("The solution is: (" + res.replaceAll("\n", ", ") + ")"); + // Output writing + try(FileWriter fileWriter = new FileWriter(outputFile)) { + fileWriter.write(res); + System.out.println("Saved to " + outputFile); + } catch(IOException e) { + System.err.println("Result cannot be written to the output file, please try other output file"); + } } } \ No newline at end of file diff --git a/src/solver/Row.java b/src/solver/Row.java index 537a55b..e2d59a2 100644 --- a/src/solver/Row.java +++ b/src/solver/Row.java @@ -14,10 +14,19 @@ public class Row { } Row normalizeRow(int index) { - return divide(row[index]); + try { + return divide(row[index]); + } catch (ArithmeticException e) { + // Ignore + // Row cannot be normalized to the zero element + return this; + } } Row divide(double v) { + if(v == 0){ + throw new java.lang.ArithmeticException("Division by zero"); + } for(int i = 0; i < row.length; i++) { row[i] = row[i] / v; } From c6dac313b4932f7f540bc9bf920435d0c2d8357f Mon Sep 17 00:00:00 2001 From: Nail Iskhakov Date: Thu, 31 Jan 2019 05:48:48 +0300 Subject: [PATCH 3/3] Minor changes --- src/solver/AugmentedMatrix.java | 11 ++++++++--- src/solver/LinearEquationSolver.java | 19 +++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/solver/AugmentedMatrix.java b/src/solver/AugmentedMatrix.java index 5c8b6e7..7254eb5 100644 --- a/src/solver/AugmentedMatrix.java +++ b/src/solver/AugmentedMatrix.java @@ -13,7 +13,7 @@ public class AugmentedMatrix { AugmentedMatrix() {} - void readMatrix(Scanner scanner) throws InputMismatchException { + public void readMatrix(Scanner scanner) throws InputMismatchException { int n = scanner.nextInt(); int m = n+1; matrix = new Row[n]; @@ -25,11 +25,11 @@ void readMatrix(Scanner scanner) throws InputMismatchException { } } - void set(int i, int j, double value) { + public void set(int i, int j, double value) { matrix[i].set(j, value); } - double get(int i, int j) { + public double get(int i, int j) { return matrix[i].get(j); } @@ -63,9 +63,14 @@ public Row getRow(int index) { return this.matrix[index]; } + /** + * Get dimensions of Augmented matrix + * @return size()[0] - number of rows, size()[1] - number of columns + */ public int[] size() { int[] size = new int[2]; size[0] = matrix.length; + // Consider that all rows have the same size, according to the class initialization size[1] = matrix[0].size(); return size; } diff --git a/src/solver/LinearEquationSolver.java b/src/solver/LinearEquationSolver.java index e1996b1..7efca22 100644 --- a/src/solver/LinearEquationSolver.java +++ b/src/solver/LinearEquationSolver.java @@ -3,9 +3,9 @@ import java.text.DecimalFormat; public class LinearEquationSolver { - AugmentedMatrix matrix; - StringBuilder logs; - double[] result; + private AugmentedMatrix matrix; + private StringBuilder logs; + private double[] result; LinearEquationSolver(AugmentedMatrix matrix) { this.matrix = new AugmentedMatrix(matrix.getMatrix()); @@ -15,7 +15,6 @@ public class LinearEquationSolver { private void transformToUpperTriangularForm() { Row currentRow; int n = matrix.size()[0]; - double coefficient; for(int i = 0; i < n; i++) { currentRow = matrix.getRow(i); normalizeRowsForTransforming(i, currentRow); @@ -28,7 +27,6 @@ private void transformToUpperTriangularForm() { private void transformToLowerTriangularForm() { Row currentRow; int n = matrix.size()[0]; - double coefficient; for(int i = n-1; i >= 0; i--) { currentRow = matrix.getRow(i); normalizeRowsForTransforming(i, currentRow); @@ -49,7 +47,8 @@ private void logMessage(String msg) { } /** - * Devide every element of matrix[j] row by the element at position i and subtracts currentRow from matrix[j] + * Devide every element of matrix[j] row by the element at position i, subtracts currentRow from matrix[j] + * and logs results * (was originally created to move duplicating code from methods) * @param i * @param j @@ -80,15 +79,15 @@ private void normalizeRowsForTransforming(int i, Row currentRow) { } } - String getLogs() { + public String getLogs() { return this.logs.toString(); } - double[] getResult() { + public double[] getResult() { return result; } - String getResultString() { + public String getResultString() { StringBuilder sb = new StringBuilder(); for(double coefficient: result) { sb.append(new DecimalFormat("#.####").format(coefficient)); @@ -98,7 +97,7 @@ String getResultString() { return sb.toString(); } - LinearEquationSolver solve() { + public LinearEquationSolver solve() { tranformToDiagonalForm(); // Get coefficients of the last column int n = this.matrix.size()[0];