public BlockMatrix(string PATH, int SIZE_BLOCK) { //PATH + "Sizebin" - путь файла для чтения //FileMode - для открытия using (var Reader = new System.IO.BinaryReader(File.Open(PATH + "Size.bin", FileMode.Open))) { M = Reader.ReadInt32(); N = M; } if (M % SIZE_BLOCK != 0) { throw new Exception("Block_Matrix: cant be separated on blocks"); } M /= SIZE_BLOCK; N /= SIZE_BLOCK; Size_Block = SIZE_BLOCK; Block = new Matrix[M][]; using (var Reader = new System.IO.BinaryReader(File.Open(PATH + "Matrix.bin", FileMode.Open))) { var LU_Decomposition = new LU_Decomposition(); for (int i = 0; i < N; i++) { Block[i] = new Matrix[N]; //определение блоков в блочной матрице for (int j = 0; j < M; j++) { Block[i][j] = new Matrix(Size_Block, Size_Block); } for (int ii = 0; ii < Size_Block; ii++) { for (int j = 0; j < M; j++) { for (int k = 0; k < Size_Block; k++) { Block[i][j].Elem[ii][k] = Reader.ReadDouble(); } } } LU_Decomposition.CreateLU(Block[i][i]); //копируем элементы из LU в блочную матрицу for (int Row = 0; Row < Size_Block; Row++) { for (int Column = 0; Column < Size_Block; Column++) { Block[i][i].Elem[Row][Column] = LU_Decomposition.LU.Elem[Row][Column]; } } } } }
//конструктор матрицы по бинарному файлу public Block_Matrix(string PATH, int SIZE_BLOCK) { //чтение размера системы using (var Reader = new BinaryReader(File.Open(PATH + "Size.bin", FileMode.Open))) { M = Reader.ReadInt32(); N = M; } //проверка размера if (M % SIZE_BLOCK != 0) { throw new Exception("Block_Matrix: error in the block size..."); } //размер матрицы M /= SIZE_BLOCK; N /= SIZE_BLOCK; Size_Block = SIZE_BLOCK; Block = new Matrix[M][]; //чтение матрицы using (var Reader = new BinaryReader(File.Open(PATH + "Matrix.bin", FileMode.Open))) { //считываем каждое значение из файла try { for (int i = 0; i < M; i++) { //выделили место под блочную матрицу Block[i] = new Matrix[N]; //выделяем место под каждый блок for (int j = 0; j < N; j++) { Block[i][j] = new Matrix(Size_Block, Size_Block); } //заполняем строки в блоках i-ой строки блочной матрицы for (int ii = 0; ii < Size_Block; ii++) { for (int j = 0; j < N; j++) { for (int k = 0; k < Size_Block; k++) { Block[i][j].Elem[ii][k] = Reader.ReadDouble(); } } } //диагональный блок необходимо преобразовать в LU-разложение var LU_Decomp = new LU_Decomposition(Block[i][i]); Block[i][i] = LU_Decomp.LU; } } catch { throw new Exception("Block_Matrix: data file is not correct..."); } } }
public Block_Matrix(string PATH, int SIZE_BLOCK, double Perturbation = 1.0) { using (var Reader = new BinaryReader(File.Open(PATH + "Size.bin", FileMode.Open))) { M = Reader.ReadInt32(); N = M; } if (M % SIZE_BLOCK != 0) { throw new Exception("Block_Matrix: Block size error"); } M /= SIZE_BLOCK; N /= SIZE_BLOCK; Size_Block = SIZE_BLOCK; Block = new Matrix[M][]; using (var Reader = new BinaryReader(File.Open(PATH + "Matrix.bin", FileMode.Open))) { try { for (int i = 0; i < M; i++) { Block[i] = new Matrix[N]; for (int j = 0; j < N; j++) { Block[i][j] = new Matrix(Size_Block, Size_Block); } for (int ii = 0; ii < Size_Block; ii++) { for (int j = 0; j < N; j++) { for (int k = 0; k < Size_Block; k++) { Block[i][j].Elem[ii][k] = Reader.ReadDouble(); if (i == j && ii == k) { Block[i][j].Elem[ii][k] *= Perturbation; } } } } var LU_Decomp = new LU_Decomposition(Block[i][i]); Block[i][i] = LU_Decomp.LU; } } catch { throw new Exception("Block_Matrix: Incorrect data file"); } } }
//метод блочной релаксации: реализация public Block_Vector Start_Solver(Block_Matrix A, Block_Vector F, double w) { //норма разности решений на двух итерациях double Norm_Xnew_Xold; //вектор результата на текущей и следующей итерации var RES = new Block_Vector(A.N, A.Size_Block); var RES_New = new Block_Vector(A.N, A.Size_Block); //LU-решатель для обращения диагональных блоков var LU_Solver = new LU_Decomposition(); //вспомогательный вектор для вычисления скобки (F - Ax) var F_Ax = new Vector(A.Size_Block); //итерации метода блочной релаксации do { Norm_Xnew_Xold = 0.0; //цикл по неизвестным for (int i = 0; i < RES.N; i++) { //инициализация суммы for (int k = 0; k < RES.Size_Block; k++) { F_Ax.Elem[k] = F.Block[i].Elem[k]; } //произведение блоков матрицы на новые X for (int j = 0; j < i; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Column = 0; Column < Current_Matrix_Block.N; Column++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Column] * Current_Vector_Block.Elem[Column]; } } } //произведение блоков матрицы на предыдущие X for (int j = i + 1; j < A.N; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Column = 0; Column < Current_Matrix_Block.N; Column++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Column] * Current_Vector_Block.Elem[Column]; } } } //решение СЛАУ с диагональной матрицей LU_Solver.LU = A.Block[i][i]; F_Ax = LU_Solver.Start_Solver(F_Ax); //формируем результат для i-ой компоненты for (int k = 0; k < RES.Size_Block; k++) { double X_NEW = (1 - w) * RES.Block[i].Elem[k] + w * F_Ax.Elem[k]; Norm_Xnew_Xold += Math.Pow(X_NEW - RES.Block[i].Elem[k], 2); RES.Block[i].Elem[k] = X_NEW; } } //норма разности решений Norm_Xnew_Xold = Math.Sqrt(Norm_Xnew_Xold); Iter++; Console.WriteLine("Iter {0,-10} {1}", Iter, Norm_Xnew_Xold); }while (Norm_Xnew_Xold > Eps && Iter < Max_Iter); return(RES); }
//блочный метод Якоби public Block_Vector Start_Solver(Block_Matrix A, Block_Vector F) { //норма разности решений на двух итерациях double Norm_Xnew_Xold; //вектор результата на текущей и следующей итерации var RES = new Block_Vector(A.N, A.Size_Block); var RES_New = new Block_Vector(A.N, A.Size_Block); //LU-решатель для обращения диагональных блоков var LU_Solver = new LU_Decomposition(); //вспомогательный вектор для вычисления скобки (F - Ax) var F_Ax = new Vector(A.Size_Block); //итерации метода Якоби do { Norm_Xnew_Xold = 0.0; //цикл по неизвестным for (int i = 0; i < RES.N; i++) { //инициализация скобки (F - Ax) F_Ax.Copy(F.Block[i]); //произведение блоков матрицы на старые X (нижний треугольник) for (int j = 0; j < i; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Column = 0; Column < Current_Matrix_Block.N; Column++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Column] * Current_Vector_Block.Elem[Column]; } } } //произведение блоков матрицы на старые X (верхний треугольник) for (int j = i + 1; j < A.N; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Column = 0; Column < Current_Matrix_Block.N; Column++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Column] * Current_Vector_Block.Elem[Column]; } } } //решение СЛАУ с диагональным блоком LU_Solver.LU = A.Block[i][i]; F_Ax = LU_Solver.Start_Solver(F_Ax); //формируем результат для i-ой компоненты и квадрат нормы разности решений for (int k = 0; k < RES.Size_Block; k++) { RES_New.Block[i].Elem[k] = F_Ax.Elem[k]; Norm_Xnew_Xold += Math.Pow(RES_New.Block[i].Elem[k] - RES.Block[i].Elem[k], 2); } } //копирование полученного результата for (int i = 0; i < RES.N; i++) { RES.Block[i].Copy(RES_New.Block[i]); } //норма разности решений Norm_Xnew_Xold = Math.Sqrt(Norm_Xnew_Xold); Iter++; Console.WriteLine("Iter {0,-10} {1}", Iter, Norm_Xnew_Xold); }while (Norm_Xnew_Xold > Eps && Iter < Max_Iter); return(RES); }
public BlockVector Solve(BlockMatrix matrixA, BlockVector vectorF) { double Norma_Xnew_Xold; Vector V_Help, V_SUM = new Vector(vectorF.Size_Block); Matrix M_Help; //для работы с диагональным блоком var LU_Solver = new LU_Decomposition(); var RES = new BlockVector(); RES.Size_Block = vectorF.Size_Block; RES.Block = new Vector[vectorF.N]; RES.N = vectorF.N; for (int i = 0; i < RES.N; i++) { //выделяем место под элемент RES.Block[i] = new Vector(RES.Size_Block); //начальное приближение x(0) for (int k = 0; k < RES.Size_Block; k++) { RES.Block[i].Elem[k] = 0.0; } } //итерация do { Norma_Xnew_Xold = 0; for (int i = 0; i < RES.N; i++) { //инициализация суммы //инициализация F for (int k = 0; k < RES.Size_Block; k++) { V_SUM.Elem[k] = vectorF.Block[i].Elem[k]; } //произведение блоков на старые x for (int j = 0; j < matrixA.N; j++) { //записывается значение ссылки, которая указывает на ij элемент M_Help = matrixA.Block[i][j]; V_Help = RES.Block[j]; for (int Row = 0; Row < M_Help.M; Row++) { for (int Column = 0; Column < M_Help.N; Column++) { V_SUM.Elem[Row] -= M_Help.Elem[Row][Column] * V_Help.Elem[Column]; } } } LU_Solver.LU = matrixA.Block[i][i]; //скобка, умноженная на обратный диагональный блок V_SUM = LU_Solver.Start_Solver(LU_Solver.LU, V_SUM); //формируем результат для i-ой компоненты for (int k = 0; k < RES.Size_Block; k++) { double X_NEW = V_SUM.Elem[k]; //вычисляем норму Norma_Xnew_Xold += Math.Pow((X_NEW - RES.Block[i].Elem[k]), 2); RES.Block[i].Elem[k] = X_NEW; } } Norma_Xnew_Xold = Math.Sqrt(Norma_Xnew_Xold); IterrationIndex++; //с каждой итерацией норма будет уменьшаться Console.WriteLine("Iter{0,-10} {1}", IterrationIndex, Norma_Xnew_Xold); }while (Norma_Xnew_Xold > Eps && IterrationIndex < MaxIterationCount); return(RES); }
public Block_Vector Start_Solver(Block_Matrix A, Block_Vector F, double w) //Блочный { double Norm_Xnew_Xold; var RES = new Block_Vector(A.N, A.Size_Block); for (int i = 0; i < RES.N; i++) { for (int k = 0; k < RES.Size_Block; k++) { RES.Block[i].Elem[k] = 1.0; } } var LU_Solver = new LU_Decomposition(); var F_Ax = new Vector(A.Size_Block); do { Norm_Xnew_Xold = 0.0; for (int i = 0; i < RES.N; i++) { for (int k = 0; k < RES.Size_Block; k++) { F_Ax.Elem[k] = F.Block[i].Elem[k]; } for (int j = 0; j < i; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Col = 0; Col < Current_Matrix_Block.N; Col++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Col] * Current_Vector_Block.Elem[Col]; } } } for (int j = i + 1; j < A.N; j++) { var Current_Matrix_Block = A.Block[i][j]; var Current_Vector_Block = RES.Block[j]; for (int Row = 0; Row < Current_Matrix_Block.M; Row++) { for (int Col = 0; Col < Current_Matrix_Block.N; Col++) { F_Ax.Elem[Row] -= Current_Matrix_Block.Elem[Row][Col] * Current_Vector_Block.Elem[Col]; } } } LU_Solver.LU = A.Block[i][i]; F_Ax = LU_Solver.Start_Solver(F_Ax); for (int k = 0; k < RES.Size_Block; k++) { double X_NEW = (1 - w) * RES.Block[i].Elem[k] + w * F_Ax.Elem[k]; Norm_Xnew_Xold += Math.Pow(X_NEW - RES.Block[i].Elem[k], 2); RES.Block[i].Elem[k] = X_NEW; } } Norm_Xnew_Xold = Math.Sqrt(Norm_Xnew_Xold); Iter++; Console.WriteLine("Iter {0,-10} {1}", Iter, Norm_Xnew_Xold); }while (Norm_Xnew_Xold > Eps && Iter < Max_Iter); return(RES); }
//Вычисление числа обусловленности public double Cond_Square_Matrix_Parallel() { if (M != N) { throw new Exception("Cond_Square_Matrix: matrix doesn't square"); } //решатель СЛАУ var LU_Solver = new LU_Decomposition(); LU_Solver.CreateLU(this.Transpose_Matrix()); //число допустимых виртуальных ядер int Number_Threads = Environment.ProcessorCount; //семафор для потоков(используется список) var Semaphors = new List <bool>(); //норма строк (разделяется по потокам) var Norma_Row_A = new double[Number_Threads]; var Norma_Row_A1 = new double[Number_Threads]; //вход в параллельную секцию //объявление объекта типа делегат //для создания объекта в параметрах конструктора передаётся анонимный метод var Thread_Solver = new Threads_Solving(Number => //лямбда-выражение { //строк для отображения матрицы //в каждом потоке хранится своя строка матрицы var A1 = new Vector(M); double S1, S2; //индексы указывающие на первую и последнюю строку для потока int Begin = N / Number_Threads * Number; int End = Begin + N / Number_Threads; //если деление было нецелочисленное, записываем в конец остаток if (Number + 1 == Number_Threads) { End += N % Number_Threads; } //решение СЛАУ для End-Begin строк for (int i = Begin; i < End; i++) { A1.Elem[i] = 1.0; A1 = LU_Solver.Start_Solver(LU_Solver.LU, A1); //нормы S1, S2 S1 = 0; S2 = 0; for (int j = 0; j < M; j++) { S1 += Math.Abs(Elem[i][j]); S2 += Math.Abs(A1.Elem[j]); A1.Elem[j] = 0.0; } //определение наибольшей из норм if (Norma_Row_A[Number] < S1) { Norma_Row_A[Number] = S1; } if (Norma_Row_A1[Number] < S2) { Norma_Row_A1[Number] = S2; } } //сигнал о завершении потока Semaphors[Number] = true; }); //отцовский поток вызывает дочерние for (int I = 0; I < Number_Threads; I++) { int Number = I; Semaphors.Add(false); //пул(очередь) потоков ThreadPool.QueueUserWorkItem(Param => Thread_Solver(Number)); } //просмотр списка семафора на наличие незавершённых потоков while (Semaphors.Contains(false)) { ; } for (int i = 1; i < Number_Threads; i++) { if (Norma_Row_A[0] < Norma_Row_A[i]) { Norma_Row_A[0] = Norma_Row_A[i]; } if (Norma_Row_A1[0] < Norma_Row_A1[i]) { Norma_Row_A1[0] = Norma_Row_A1[i]; } } return(Norma_Row_A[0] * Norma_Row_A1[0]); }