diff --git a/.idea/misc.xml b/.idea/misc.xml
index a165cb3..df60b67 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/src/plan.txt b/src/plan.txt
new file mode 100644
index 0000000..1a17dd1
--- /dev/null
+++ b/src/plan.txt
@@ -0,0 +1,60 @@
+На этой стадии нужно написать программу, которая
+1.считывает коэффициенты системы линейных уравнений из файла.
+1.1 Первая строка содержит N - число переменных и уравнений.
+1.2 Каждая последующая строка - N+1 чисел - N коэффициентов уравнения,
+ и последнее число - правая часть уравнения - константа.
+2.решает систему линейных уравнений
+3.записывает ответ в другой файл.
+3.1 В файл должны быть записаны только ответы, разделенные "\n".
+4.пути к файлам следует передавать как аргументы командной строки.
+5.Весь процесс решения/преобразований со строками должен быть выведен на консоль.
+6.Постарайтесь создать различные классы такие как: Matrix, Row, LinearEquation.
+Пример вывода: The lines which start with > represent the user input.
+
+> java Solver -in in.txt -out out.txt
+Start solving the equation.
+Rows manipulation:
+-2 * R1 + R2 -> R2
+-3 * R1 + R3 -> R3
+0.5 * R2 -> R2
+-3 * R2 + R3 -> R3
+-2 * R3 -> R3
+3.5 * R3 + R2 -> R2
+-2 * R3 + R1 -> R1
+-1 * R2 + R1 -> R1
+The solution is: (1.0, 2.0, 3.0)
+Saved to file out.txt
+
+Алгоритм преобразований.
+1.Обнулить все коэффициенты первого столбца кроме первого, он должен стать = 1.
+2.Последовательно обнулить все коэффициенты второго и последующего столбцов
+пока в последней строке все коэффициенты не обнулятся кроме последнего столбца.
+3.Вторая часть алгоритма - обнулять коэффициенты выше диагонали,
+начиная с последней строки до первой.
+4.После этих преобразований решением уравнений будет правая часть матрицы.
+Стадия 4.
+Может быть случай, когда коэффициент, на который мы будем умножать будет равен 0.
+Поэтому перед операцией умножения нужно проверить, коэффициент на равенство 0.
+Если нужно искать ненулевой элемент ниже и правее.
+1. Если ненулевой элемент ниже, то нужно переставить строки местами
+2. Если ниже все элементы нулевые, то продолжаем искать правее
+от элемента. Если находим, переставляем столбцы,строки.
+Состояние столбцов/строк до перестановки необходимо запомнить,
+чтобы после реализации вернуть все на место в исходном порядке и
+вывести решение в нужном порядке. В общей сложности может быть
+много перестановок.
+Если ненулевой элмент не находится ниже и правее, то ищется
+ненулевой элемент по всей левой части матрицы и при нахождении
+переставляем соответствущие строки и столбцы.
+Если ненулевой элемент не найден, первая часть алгоритма завершается.
+
+После этого проверяем на количество решений.
+1. все коэффициенты левой части нулевые, п.ч. ненулевая - нет решений.
+2. если количество ненулевых элементов на главной диагонали
+совпадает с количеством уравнений (в п.ч. не нули) - одно решение
+3. если на главной дигонали есть нулевые элементы + в п.ч.нули
+-> бесконечно много решений.
+C1,C2,C3(1<->2)C2,C1,C3(1<->3)C3,C1,C2
+colMove[1]=3
+colMove[2]=1
+colMove[3]=2
diff --git a/src/solver/InvalidDataFileFormat.java b/src/solver/InvalidDataFileFormat.java
new file mode 100644
index 0000000..589a023
--- /dev/null
+++ b/src/solver/InvalidDataFileFormat.java
@@ -0,0 +1,7 @@
+package solver;
+
+public class InvalidDataFileFormat extends Exception{
+ public InvalidDataFileFormat(String msg, Exception cause) {
+ super(msg, cause);
+ }
+}
diff --git a/src/solver/Main.java b/src/solver/Main.java
index 4404714..5c8706d 100644
--- a/src/solver/Main.java
+++ b/src/solver/Main.java
@@ -1,7 +1,125 @@
package solver;
+import java.io.File;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
public class Main {
- public static void main(String[] args) {
- System.out.print("Hello world!");
+ static String inFile;
+ static String outFile;
+ public static void main(String[] args) throws InvalidDataFileFormat {
+ //get_in_file
+ if (args.length!=4) {
+ System.out.println("Invalid comand-line arguments");
+ return;
+ }
+
+ for (int i = 0; i < args.length; i+=2) {
+ if (args[i].equalsIgnoreCase("-in"))
+ inFile = args[i+1];
+ else if (args[i].equalsIgnoreCase("-out"))
+ outFile = args[i+1];
+ }
+ try {
+ List lines = Files.readAllLines( Paths.get(inFile));
+ int n=0,v=0;
+ int k=0;
+ try {
+ for (String s:lines.get(0).split("\\s")) {
+ if (k==0)
+ n = Integer.parseInt(s);//количество строк - уравнений
+ else
+ v = Integer.parseInt(s);//количество столбцов - переменных
+ k++;
+ }
+ if (v==0) v=n;
+ }
+ catch (NumberFormatException e){
+ throw new InvalidDataFileFormat(
+ //String.format("The string '%s' cannot be parsed as an array of numbers", s),
+ String.format("Incorrect data file format, '%s' cannot be parsed as two numbers", lines.get(0)),
+ e);
+ }
+ lines.remove(0);
+ if (lines.size() != n) {
+ throw new InvalidDataFileFormat("Incorrect data file format, count of data rows isn't equal n", null);
+ }
+ System.out.println("Start solving the equation.\n" +
+ "Rows manipulation:");
+ Matrix m = new Matrix(n,v);
+ for (String line : lines) {
+ m.addRow(lines.indexOf(line), line);
+ }
+ String manipulation;
+ //m.otladka = true;
+ m.print();
+ for (int i = 0; i < m.M; i++) {
+ while (true)
+ {
+ manipulation = m.rows[i].transform1(i);
+ if (!manipulation.equals("")) {
+ System.out.println(manipulation);
+ m.print();
+ if (!manipulation.contains("<->")) break;
+ } else break;
+ };
+
+ for (int j = i+1; j < m.N; j++) {
+ manipulation = m.rows[j].transform0(i, m.rows[i]);
+ if (!manipulation.equals("")) {
+ System.out.println(manipulation);
+ m.print();
+ }
+ }
+ }
+ int check = m.checkSolution();
+
+ String result="";
+ switch (check) {
+ case 0: {
+ result = "Infinite solutions";
+ System.out.println(result);
+ break;
+ }
+ case -1: {
+ result = "No solutions";
+ System.out.println(result);
+ break;
+ }
+ case 1: {
+ System.out.println("-------");
+ for (int i = m.N - 1; i >= 0; i--) {
+ for (int j = i - 1; j >= 0; j--) {
+ manipulation = m.rows[j].transform0(i, m.rows[i]);
+ if (!manipulation.equals("")) {
+ System.out.println(manipulation);
+ m.print();
+ }
+ }
+ }
+ result = m.printSolution();
+ break;
+ }
+ default:break;
+ }
+ File file = new File(outFile);
+ try (FileWriter writer = new FileWriter(file)) {
+ writer.write(result);
+ System.out.printf("Saved to file %s\n",outFile);
+ } catch (IOException e) {
+ System.out.printf("File writing error %s", e.getMessage());
+ }
+
+ }
+ catch (IOException e){
+ System.out.println("File reading error: " + inFile);
+ }
+ catch (InvalidDataFileFormat | ParsingArrayException e){
+ System.out.println(e.getMessage());
+ }
}
}
\ No newline at end of file
diff --git a/src/solver/Matrix.java b/src/solver/Matrix.java
new file mode 100644
index 0000000..5ef9a70
--- /dev/null
+++ b/src/solver/Matrix.java
@@ -0,0 +1,176 @@
+package solver;
+
+import java.util.Arrays;
+
+//import java.util.Arrays;
+class Pos{
+ int x;
+ int y;
+
+ public Pos(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+ public String asString(){
+ return this.x+","+this.y;
+ }
+}
+
+public class Matrix {
+ public static final double threshold = 0.000001;
+ int N;//количество строк
+ int M;//количество столбцов
+ Row[] rows;
+ int[] colMove;
+ int iteration = 0;
+ private boolean colsSwaped = false;
+
+ public boolean otladka = false;
+
+ public static boolean compareDouble(double d1, double d2){
+ return (Math.abs(d1 - d2) < threshold);
+ }
+
+ public Matrix(int n, int m) {
+ N = n;
+ M = m;
+ rows = new Row[n];
+ colMove = new int[m];//сюда будем записывать перемещения столбов
+ for (int i = 0; i < M; i++)
+ this.colMove[i] = i;
+ }
+
+ public void addRow(int index, String str) throws ParsingArrayException {
+ this.rows[index] = new Row(index+1, M+1, this);
+ this.rows[index].fillRow(str);
+ }
+
+ public void print(){
+ if (!otladka) return;
+ for (Row r:this.rows) {
+ System.out.println(r.asString());
+ }
+ }
+
+ public String printSolution(){
+ if (colsSwaped) return printSolution1();
+ String sOut = "The solution is: (";
+ String result="";
+ double s;
+ for (Row r:this.rows) {
+ s =r.getCol(this.M);
+ result+=s+"\n";
+ sOut += s+", ";
+ }
+ System.out.println(sOut.replaceAll(",\\s$", ")"));
+ return result;
+ }
+
+ private String printSolution1(){
+ String sOut = "The solution is: (";
+ double[] d= new double[colMove.length];
+ String result="";
+ for (int i = 0; i < colMove.length; i++) {
+ d[colMove[i]]=this.rows[i].getCol(this.M);
+ }
+ for (int i = 0; i < colMove.length; i++) {
+ result+=d[i]+"\n";
+ sOut += d[i]+", ";
+ }
+ System.out.println(sOut.replaceAll(",\\s$", ")"));
+ return result;
+ }
+
+ public String swapRows(int src, int dest){
+ try {
+ Row r1 = this.rows[src];
+ Row r2 = this.rows[dest];
+ iteration++;
+ String result = String.format("%d: %s<->%s", iteration, r1.getName(), r2.getName());
+ Row tmp;
+ tmp = this.rows[dest];
+ this.rows[dest] = this.rows[src];
+ this.rows[src] = tmp;
+ this.rows[src].setMoved(true, src + 1);
+ this.rows[dest].setMoved(true, dest + 1);
+ return result;
+ }
+ catch (Exception e){
+ System.out.println(String.format("SwapRow(src=%d,dest=%d)",src,dest));
+ throw e;
+ }
+ }
+
+
+ public String swapColumns(int src, int dest){
+ for (Row r:this.rows) {
+ r.swapCells(src,dest);
+ }
+ int tmp =this.colMove[dest];
+ this.colMove[dest] = this.colMove[src];
+ this.colMove[src] = tmp;
+ iteration++;
+ colsSwaped = true;
+ return String.format("%d; C%d<->C%d",iteration, src,dest);
+ }
+
+ public int findNonZeroBelow(int col, Row rowBelow){
+ for (int i = rowBelow.getRowNum()/*-1+1*/; i < N; i++) {
+ //if (this.rows[i].getCol(col)!=0) return i;
+ if (!compareDouble(this.rows[i].getCol(col),0)) return i;
+ }
+ return -1;
+ }
+
+ public int findNonZeroRighter(int colAfterIndex, Row row){
+ for (int j = colAfterIndex+1; j < M; j++) {
+// if (row.getCol(j)!=0) return j;
+ if (!compareDouble(row.getCol(j),0)) return j;
+ }
+ return -1;
+ }
+
+ public Pos findNonZeroEverywhere(int colAfterIndex, Row rowBelow){
+ int fromRow=0;
+ if (rowBelow == null) fromRow = 0;
+ else fromRow = rowBelow.getRowNum();
+ for (int i = fromRow; i < N; i++) {
+ for (int j = colAfterIndex+1; j < M; j++) {
+// if (this.rows[i].getCol(j)!=0) return new Pos(i,j);
+ if (!compareDouble(this.rows[i].getCol(j),0)) return new Pos(i,j);
+ }
+ }
+ return null;
+ }
+
+ public Pos getNumberOfZeroRows(){
+ //в ч запишем количество нулевых строк,
+ //в y количество нулевых строк с ненулевой правой частью
+ Pos result= new Pos(0,0);
+ int cnt0 =0, cnt1 =0;
+ for (Row r:this.rows) {
+ cnt0=0;
+ for (int i = 0; i < M+1; i++) {
+ //if (r.getCol(i)!=0) {
+ if (!compareDouble(r.getCol(i),0)){
+ if (i==M) result.y++;
+ break;
+ }
+ cnt0++;
+ }
+ if (cnt0==M+1) result.x++;
+ }
+ return result;
+ }
+
+ public int checkSolution(){
+ Pos zeroRowsCnt = this.getNumberOfZeroRows();
+ if (otladka)
+ System.out.println(zeroRowsCnt.asString());
+ if (zeroRowsCnt.y>0) return -1;//no solutions
+ int cntEq = this.N-zeroRowsCnt.x;//количество ненулевых уравнений
+ if (cntEq==this.M) return 1;//one solution
+ if (cntEq -1)
+ return this.owner.swapRows(this.rowNum-1,nonZeroInd);
+ nonZeroInd = this.owner.findNonZeroRighter(index,this);
+ if (nonZeroInd > -1)
+ return this.owner.swapColumns(index,nonZeroInd);
+ //поиск по всей матрице
+ Pos pos = this.owner.findNonZeroEverywhere(index,this);
+ if (pos == null) return "";
+ return this.owner.swapColumns(index,pos.y)+";"+
+ this.owner.swapRows(this.rowNum-1, pos.x);
+ }
+ double koef = 1/this.data[index];
+ this.mult(koef);
+ this.data[index] = 1;
+// return String.format("%-8.2f %n",koef) +" * "+this.getName()+" -> "+this.getName();
+ return String.format("%d: %.2f * %s -> %s",++this.owner.iteration, koef,this.getName(),this.getName());
+ }
+
+ public String transform0(int index, Row r){
+ if (Matrix.compareDouble(this.data[index],0)) return "";//"already transformed0";
+ double koef = -1 * this.data[index];
+ this.add1(r,koef);
+ this.data[index] = 0;
+ this.owner.iteration++;
+// return koef + " * "+ r.getName() + " + "+ this.getName()+" -> "+this.getName();
+ return String.format("%d: %.3f * %s -> %s",this.owner.iteration, koef,r.getName(),this.getName());
+ }
+
+ public double getCol(int index){
+ return this.data[index];
+ }
+
+ public void fillRow(String s) throws ParsingArrayException {
+ String[] str = s.split("\\s+");
+ try {
+ if (str.length!=this.colCnt)
+ throw new ParsingArrayException(
+ String.format("The string '%s' cannot be parsed correctly. It has to contain %d numbers", s, this.colCnt+1),
+ null);
+ for (int i = 0; i < str.length; i++) {
+ this.data[i] = Double.parseDouble(str[i]);
+ }
+ } catch(NumberFormatException e){
+ throw new ParsingArrayException(
+ String.format("The string '%s' cannot be parsed as an array of numbers", s),
+ e);
+ }
+ catch (ArrayIndexOutOfBoundsException e){
+ throw new ParsingArrayException(
+ String.format("The string '%s' cannot be parsed correctly, count of numbers is incorrect", s),
+ e);
+ }
+ }
+
+ public String asString() {
+ String s="";
+ for (double d:this.data) {
+ s +=String.format("%-10.3f ",d);
+ //s +=String.format("%.3f ",d);
+ };
+ return this.getName()+((this.getOldRowNum()!=this.getRowNum())?String.format("(%d)",this.getOldRowNum()):"")+": "+ s.trim();
+ }
+
+ public boolean isMoved() {
+ return isMoved;
+ }
+
+ public void setMoved(boolean moved, int newRow) {
+ isMoved = moved;
+ if (moved) {
+ /*if (this.oldRowNum == this.rowNum) {
+ this.oldRowNum = rowNum;
+ }*/
+ this.rowNum = newRow;
+ }
+ if (this.rowNum == this.oldRowNum) isMoved = false;
+ }
+ public void swapCells(int src, int dest){
+ double tmp;
+ tmp = this.data[dest];
+ this.data[dest] = this.data[src];
+ this.data[src] = tmp;
+ }
+}