Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/project.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions in.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
3
1 1 2 9
2 4 -3 1
3 6 -5 0
3 changes: 3 additions & 0 deletions out.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1
2
3
79 changes: 79 additions & 0 deletions src/solver/AugmentedMatrix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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() {}

public void readMatrix(Scanner scanner) throws InputMismatchException {
int n = scanner.nextInt();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never use only one letter in the name. Variable should represent the value it was created for.

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());
}
}
}

public void set(int i, int j, double value) {
matrix[i].set(j, value);
}

public double get(int i, int j) {
return matrix[i].get(j);
}

@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];
}

/**
* 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;
}


}
115 changes: 115 additions & 0 deletions src/solver/LinearEquationSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package solver;

import java.text.DecimalFormat;

public class LinearEquationSolver {
private AugmentedMatrix matrix;
private StringBuilder logs;
private double[] result;

LinearEquationSolver(AugmentedMatrix matrix) {
this.matrix = new AugmentedMatrix(matrix.getMatrix());
this.logs = new StringBuilder();
}

private void transformToUpperTriangularForm() {
Row currentRow;
int n = matrix.size()[0];
for(int i = 0; i < n; i++) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "for"

currentRow = matrix.getRow(i);
normalizeRowsForTransforming(i, currentRow);
for(int j = i + 1; j < n; j++) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "for"

subtractRowsForTransforming(i,j,currentRow);
}
}
}

private void transformToLowerTriangularForm() {
Row currentRow;
int n = matrix.size()[0];
for(int i = n-1; i >= 0; i--) {
currentRow = matrix.getRow(i);
normalizeRowsForTransforming(i, currentRow);
for(int j = i-1; j >= 0; j--) {
subtractRowsForTransforming(i,j,currentRow);
}
}
}

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, subtracts currentRow from matrix[j]
* and logs results
* (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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "if"

matrix.getRow(j).normalizeRow(i);
logMessage(String.format("R%d / %s - R%d -> R%d", j, new DecimalFormat("#.###").format(coefficient), i, j));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you are better off having static String variable with "#.###"

} 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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "if"

currentRow.normalizeRow(i);
logMessage(String.format("R%d / %s -> R%d", i, new DecimalFormat("#.###").format(coefficient), i));
}
}

public String getLogs() {
return this.logs.toString();
}

public double[] getResult() {
return result;
}

public String getResultString() {
StringBuilder sb = new StringBuilder();
for(double coefficient: result) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "for"

sb.append(new DecimalFormat("#.####").format(coefficient));
sb.append("\n");
}
sb.deleteCharAt(sb.length()-1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need spaces after "sb.length()" and before "-1"

return sb.toString();
}

public 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++) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "for"

result[i] = matrix.get(i, m-1);
}
return this;
}

public AugmentedMatrix getMatrix() {
return matrix;
}
}
93 changes: 92 additions & 1 deletion src/solver/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,98 @@
package solver;

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 getHelp() {
String helpMsg = "This program is intended to solve Linear Equations with any amount of variables using Gauss-Jordan Elimination. \n\n" +
Copy link

@edvardyanushkevich edvardyanushkevich Feb 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User StringBuilder (of course the compiler will use StringBuilder automatically, but the usage of it is more look like Builder pattern).

"Options: " +
"\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 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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method main is very big. If your method does two or three different things at a time then you should consider splitting the functionality of this method into other methods (single responsibility principle) and just try to make your methods as small as possible.

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(getHelp());
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;
}

// Input matrix output
System.out.println("Input matrix:");
System.out.println(matrix);


// Solving equation
System.out.println("Start solving linear equation.");
LinearEquationSolver solver = new LinearEquationSolver(matrix);
String res = solver.solve().getResultString();
System.out.println("Rows manipulation:");
System.out.println(solver.getLogs());

System.out.println("The solution is: (" + res.replaceAll("\n", ", ") + ")");

// Output writing
try(FileWriter fileWriter = new FileWriter(outputFile)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need space after "try"

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");
}
}
}
62 changes: 62 additions & 0 deletions src/solver/Row.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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) {
try {
return divide(row[index]);
} catch (ArithmeticException e) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the word "ignore" after the ArithmeticException keyword.

// 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");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can simply write: throw new ArithmeticException("Division by zero");

}
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;
}
}