/// <summary> /// Замена колонны указанным вектором (для метода Крамера) /// </summary> /// <param name="ColumnNumber">Номер колонны</param> /// <param name="newColumn">Новая колонна</param> /// <returns></returns> public CSqMatrix ColumnSwap(int ColumnNumber, CVectors newColumn) { SqMatrix R = this.Re.ColumnSwap(ColumnNumber, newColumn.Re); SqMatrix I = this.Im.ColumnSwap(ColumnNumber, newColumn.Im); return(new CSqMatrix(R, I)); }
/// <summary> /// Характеристический многочлен заданной матрицы /// </summary> /// <param name="M"></param> /// <returns></returns> public static Polynom CharactPol(SqMatrix M) { Polynom p = new Polynom(M.n); double sum; SqMatrix A = new SqMatrix(M); //заполнение массива треков double[] tr = new double[A.n]; for (int i = 0; i < A.n; i++) { tr[i] = A.Track; A *= M; } p.coef[(int)p.degree] = 1 * Math.Pow(-1, A.n); int k = 0; for (int i = (int)p.degree - 1; i >= 0; i--) { sum = 0; k++; for (int j = 0; j < k; j++) { sum += tr[k - j - 1] * p.coef[(int)p.degree - j]; } sum *= -1; sum /= k; p.coef[i] = sum; } return(p); }
//public override bool Nulle()//нулевая ли матрица? //{ // for (int i = 0; i < n; i++) // { // for (int j = 0; j < n; j++) // { // if (matrix[i, j] != 0) return false; // } // } // return true; //} /// <summary> /// Единичная матрица /// </summary> /// <param name="n"></param> /// <returns></returns> public static SqMatrix E(int n) { SqMatrix M = new SqMatrix(n); for (int i = 0; i < n; i++) { M[i, i] = 1; } return(M); }
/// <summary> /// Единичная матрица /// </summary> public static SqMatrix I(int n) { SqMatrix A = new SqMatrix(n); for (int i = 0; i < n; i++) { A[i, i] = 1; } return(A); }
/// <summary> /// Создать матрицу как угловую подматрицу размерности k /// </summary> /// <param name="A"></param> /// <param name="k"></param> public SqMatrix(SqMatrix A, int k) : base(k, k) { for (int i = 0; i < this.n; i++) { for (int j = 0; j < this.n; j++) { this[i, j] = A[i, j]; } } }
/// <summary> /// Подобная матрица, если задана ортогональная матрица преобразования /// </summary> /// <param name="M"></param> /// <returns></returns> public SqMatrix ConvertToSimilar(SqMatrix M, bool directly = true) { if (directly) { return((SqMatrix)(M.Transpose() * this * M)); } else { return((SqMatrix)(M * this * M.Transpose())); } }
/// <summary> /// Конструктор копирования /// </summary> /// <param name="M"></param> public SqMatrix(SqMatrix M) { this.n = this.m = M.n; this.matrix = new double[n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { this[i, j] = M[i, j]; } } }
//операторы //сложение public static SqMatrix operator +(SqMatrix A, SqMatrix B) { SqMatrix C = new SqMatrix(A.n); for (int i = 0; i < A.n; i++) { for (int j = 0; j < A.n; j++) { C[i, j] = A[i, j] + B[i, j]; } } return(C); }
//Умножение на число public static SqMatrix operator *(SqMatrix A, double Ch) { SqMatrix q = new SqMatrix(A.n); for (int i = 0; i < A.n; i++) { for (int j = 0; j < A.n; j++) { q[i, j] = A[i, j] * Ch; } } return(q); }
//вычитание public static SqMatrix operator -(SqMatrix A, SqMatrix B) { SqMatrix R = new SqMatrix(A.n); for (int i = 0; i < A.n; i++) { for (int j = 0; j < A.n; j++) { R[i, j] = A[i, j] - B[i, j]; } } return(R); }
/// <summary> /// Подматрица размерности len /// </summary> /// <param name="len"></param> /// <returns></returns> public SqMatrix SubMatrix(int len) { SqMatrix r = new SqMatrix(len); for (int i = 0; i < len; i++) { for (int j = 0; j < len; j++) { r[i, j] = this[i, j]; } } return(r); }
/// <summary> /// Квадратная подматрица, порождённая пересечением таких строк и столбцов /// </summary> /// <param name="m"></param> /// <returns></returns> /// <remarks>Нумерация строк должна начинаться с единицы</remarks> public SqMatrix SubMatrix(params int[] m) { SqMatrix M = new SqMatrix(m.Length); for (int i = 0; i < m.Length; i++) { for (int j = 0; j < m.Length; j++) { M[i, j] = this[m[i] - 1, m[j] - 1]; } } return(M); }
private static Complex[,] mas(SqMatrix A, SqMatrix B) { var res = new Complex[A.RowCount, A.ColCount]; for (int i = 0; i < A.RowCount; i++) { for (int j = 0; j < A.ColCount; j++) { res[i, j] = A[i, j] + Complex.I * B[i, j]; } } return(res); }
/// <summary> /// Перевод матрицы в одномерный массив /// </summary> /// <param name="M"></param> /// <returns></returns> public static double[] ToDoubleMas(SqMatrix M) { double[] res = new double[M.m * M.m]; int y = 0; for (int i = 0; i < M.n; i++) { for (int j = 0; j < M.m; j++) { res[y++] = M[i, j]; } } return(res); }
/// <summary> /// Является ли матрица положительно определённой /// </summary> /// <returns></returns> public bool IsPositCertain() { //if (!this.IsSymmetric()) return false; for (int i = 0; i < this.n; i++) { SqMatrix M = new SqMatrix(this, i + 1); double s = M.Det; if (s <= 0) { return(false); } } return(true); }
/// <summary> /// Замена столбца матрицы на указанный вектор (для метода Крамера) /// </summary> /// <param name="ColumnNumber">Номер стоблца, начиная с 1</param> /// <param name="NewColumn">Сам вектор (если вектор)</param> /// <remarks>Если вектор короткий, заменится лишь часть колонны, а если длинный, будет исключение</remarks> /// <returns></returns> public SqMatrix ColumnSwap(int ColumnNumber, Vectors NewColumn) { SqMatrix mat = new SqMatrix(this); if (ColumnNumber > mat.ColCount || ColumnNumber <= 0 || NewColumn.Deg > mat.RowCount) { throw new Exception("В матрице нет столбца с таким номером либо вектор слишком длинный"); } ColumnNumber--; for (int i = 0; i < NewColumn.Deg; i++) { mat[i, ColumnNumber] = NewColumn[i]; } return(mat); }
/// <summary> /// Обратная матрица по Гауссу /// </summary> /// <returns></returns> public CSqMatrix Invert(bool correct = false) { CSqMatrix mResult = SqMatrix.E(this.ColCount); CSqMatrix mCur = new CSqMatrix(this); CVectors rTmp, eTmp; for (int i = 0; i < this.ColCount; i++) //Цикл по строкам сверху-вниз { int max = MaxLine(i, i); if (max != i) { rTmp = mCur.GetLine(max); eTmp = mResult.GetLine(max); mCur.MinusVector(i, rTmp * (-1)); mResult.MinusVector(i, eTmp * (-1)); //Complex y = new Complex(mCur[i, max]); //mCur.DivByLine(i, y); //mResult.DivByLine(i, y); } //Заединичить вервую строку Complex dItem = new Complex(mCur[i, i]); mCur.DivByLine(i, dItem); mResult.DivByLine(i, dItem); rTmp = mCur.GetLine(i); eTmp = mResult.GetLine(i); //Забить нулями вертикаль for (int j = 0; j < this.ColCount; j++) { if (i != j) { Complex con = new Complex(mCur[j, i]); mCur.MinusVector(j, rTmp * con); mResult.MinusVector(j, eTmp * con); } } //mCur.PrintMatrix(); Console.WriteLine(); //mResult.PrintMatrix(); Console.WriteLine(); } if (!correct) { return(mResult); } return(ReverseCorrect(this, mResult, 1e-16, 100)); }
/// <summary> /// Полином от матрицы /// </summary> /// <param name="A"></param> /// <returns></returns> public SqMatrix Value(SqMatrix A) { SqMatrix I = SqMatrix.I(A.n); SqMatrix sum = this.coef[(int)this.degree] * I; if (this.degree > 0) { for (int i = (int)(this.degree - 1); i >= 0; i--) { sum *= A; sum += this.coef[i] * I; } } return(sum); }
//произведение public static SqMatrix operator *(SqMatrix A, SqMatrix B) { SqMatrix r = new SqMatrix(A.n); for (int i = 0; i < A.n; i++) { for (int j = 0; j < A.n; j++) { for (int k = 0; k < B.n; k++) { r[i, j] += A[i, k] * B[k, j]; } } } return(r); }
/// <summary> /// Уточнение обратной матрицы /// </summary> /// <param name="A">Исходная матрица</param> /// <param name="Reverse">Обратная марица</param> /// <param name="eps">Точность</param> /// <returns></returns> public static SqMatrix ReverseCorrect(SqMatrix A, SqMatrix Reverse, double eps = 0.001, int stepcount = 1000, bool existnorm = false) { SqMatrix E = SqMatrix.E(A.RowCount), R = new SqMatrix(Reverse); int i = 0; if ((E - A * R).CubeNorm < 1 || existnorm) { while ((E - A * R).CubeNorm > eps && i < stepcount) { R *= (2 * E - A * R); //(E - A * R).CubeNorm.Show(); i++; } } return(R); }
static ODU() { E1 = new SqMatrix(2); E1[1, 1] = 1; E2 = new SqMatrix(3); E2[1, 0] = 0.5; E2[1, 1] = 0.5; E2[2, 2] = 1; H = new SqMatrix(4); H[1, 0] = 1.0 / 3; H[1, 1] = 1.0 / 3; H[2, 0] = 2.0 / 3; H[2, 2] = 2.0 / 3; H[3, 1] = 1.0 / 4; H[3, 3] = 3.0 / 4; RK3 = new SqMatrix(4); RK3[1, 0] = 0.5; RK3[1, 1] = 0.5; RK3[2, 0] = 1; RK3[2, 2] = 1; RK3[3, 1] = 1.0 / 6; RK3[3, 2] = 4.0 / 6; RK3[3, 3] = 1.0 / 6; Rk4 = new SqMatrix(5); Rk4[1, 0] = 0.5; Rk4[1, 1] = 0.5; Rk4[2, 0] = 0.5; Rk4[2, 2] = 0.5; Rk4[3, 0] = 1; Rk4[3, 3] = 1; Rk4[4, 1] = 1.0 / 6; Rk4[4, 2] = 2.0 / 6; Rk4[4, 3] = 2.0 / 6; Rk4[4, 4] = 1.0 / 6; P38 = new SqMatrix(5); P38[1, 0] = 1.0 / 3; P38[1, 1] = 1.0 / 3; P38[2, 0] = 2.0 / 3; P38[2, 1] = -1.0 / 3; P38[2, 2] = 1; P38[3, 0] = 1; P38[3, 1] = 1; P38[3, 2] = -1; P38[3, 3] = 1; P38[4, 1] = 1.0 / 8; P38[4, 2] = 3.0 / 8; P38[4, 3] = 3.0 / 8; P38[4, 4] = 1.0 / 8; F = new Matrix(5, 4); F[1, 0] = 1; F[1, 1] = 1; F[2, 0] = 0.5; F[2, 1] = 0.25; F[2, 2] = 0.25; F[3, 1] = 0.5; F[3, 2] = 0.5; F[4, 1] = 1.0 / 6; F[4, 2] = 1.0 / 6; F[4, 3] = 4.0 / 6; C = new Matrix(6, 5); C[1, 0] = 0.25; C[1, 1] = 0.25; C[2, 0] = 0.5; C[2, 2] = 0.5; C[3, 0] = 1; C[3, 1] = 1; C[3, 3] = -2; C[3, 4] = 2; C[4, 1] = 1; C[4, 2] = -2; C[4, 3] = 2; C[5, 1] = 1.0 / 6; C[5, 3] = 4.0 / 6; C[5, 4] = 1.0 / 6; }
/// <summary> /// Обратная матрица по Гауссу /// </summary> /// <returns></returns> public SqMatrix Invert() { SqMatrix mResult = SqMatrix.E(this.ColCount); /* * Получать "1" на элементе главной диагонали, а потом * Занулять оставшиеся элементы * */ SqMatrix mCur = new SqMatrix(this); //mCur.PrintMatrix(); Console.WriteLine(); //mResult.PrintMatrix(); Console.WriteLine(); for (int i = 0; i < this.ColCount; i++) //Цикл по строкам сверху-вниз { //Заединичить вервую строку double dItem = mCur[i, i]; mCur.DivByLine(i, dItem); mResult.DivByLine(i, dItem); //mCur.PrintMatrix(); Console.WriteLine(); //mResult.PrintMatrix(); Console.WriteLine(); Vectors rTmp = mCur.GetLine(i); Vectors eTmp = mResult.GetLine(i); //Забить нулями вертикаль for (int j = 0; j < this.ColCount; j++) { if (i != j) { double con = mCur[j, i]; mCur.MinusVector(j, rTmp * con); mResult.MinusVector(j, eTmp * con); } } //mCur.PrintMatrix(); Console.WriteLine(); //mResult.PrintMatrix(); Console.WriteLine(); } return(mResult); }
/// <summary> /// Уточнение обратной матрицы /// </summary> /// <param name="A">Исходная матрица</param> /// <param name="Reverse">Обратная марица</param> /// <param name="eps">Точность</param> /// <returns></returns> public static CSqMatrix ReverseCorrect(CSqMatrix A, CSqMatrix Reverse, double eps = 0.001, int stepcount = 1000, bool existnorm = false) { CSqMatrix E = new CSqMatrix(SqMatrix.E(A.RowCount)), E2 = E * 2, R = new CSqMatrix(Reverse), Rold = new CSqMatrix(Reverse); int i = 0;//i.Show(); double epsold = (E - A * R).CubeNorm, epsnew = epsold; //if (epsold < 1 || existnorm) while (epsnew > eps && i < stepcount) { R *= (E2 - A * R);//epsold.Show(); //(E - A * R).CubeNorm.Show(); epsold = epsnew; epsnew = (E - A * R).CubeNorm; if (epsnew >= epsold) /*$"{epsold} {epsnew}".Show();*/ return { (Rold); } Rold = new CSqMatrix(R); i++; } return(R); }
/// <summary> /// Минор элемента матрицы (точнее, алгебраическое дополнение) /// </summary> /// <returns></returns> public double Minor(int i, int j) { if ((i >= n) || (j >= n)) { throw new Exception("Вызов элемента, которого нет в матрице"); } if (this.n <= 1) { throw new Exception("Размерность матрицы слишком мала"); } if (this.n == 2) { return(Math.Pow(-1, i + j) * this[3 - i - 2, 3 - j - 2]); } //int Inew = i--,Jnew=j--; SqMatrix M = new SqMatrix(this.n - 1); int a = 0, b = 0; for (int ii = 0; ii < this.n; ii++) { if (ii != i) { for (int jj = 0; jj < this.n; jj++) { if (jj != j) { M[a, b] = this[ii, jj]; //Console.WriteLine("{0} {1} {2} {3}", a,b,ii,jj); b++; } } a++; b = 0; } } //M.PrintMatrix(); return(Math.Pow(-1, i + 1 + j + 1) * M.Det); }
/// <summary> /// Конструктор по действительной и мнимой части матрицы /// </summary> /// <param name="R"></param> /// <param name="I"></param> public CSqMatrix(SqMatrix R, SqMatrix I) : this(mas(R, I)) { }