/// <summary> /// Computes the product of two square matrices. /// </summary> /// <param name="A">The first matrix.</param> /// <param name="B">The second matrix.</param> /// <returns>The product <paramref name="A"/> * <paramref name="B"/>.</returns> /// <remarks> /// <para>Note that matrix multiplication is not commutative, i.e. M1*M2 is generally not the same as M2*M1.</para> /// <para>Matrix multiplication is an O(N<sup>3</sup>) process.</para> /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="A"/> or <paramref name="B"/> is <see langword="null"/>.</exception> /// <exception cref="DimensionMismatchException">The dimension of <paramref name="A"/> is not the same as the dimension of <paramref name="B"/>.</exception> public static SquareMatrix operator *(SquareMatrix A, SquareMatrix B) { // this is faster than the base operator, because it knows about the underlying structure if (A == null) { throw new ArgumentNullException(nameof(A)); } if (B == null) { throw new ArgumentNullException(nameof(B)); } if (A.dimension != B.dimension) { throw new DimensionMismatchException(); } double[] abStore = MatrixAlgorithms.Multiply( A.store, A.offset, A.rowStride, A.colStride, B.store, B.offset, B.rowStride, B.colStride, A.dimension, A.dimension, A.dimension ); return(new SquareMatrix(abStore, A.dimension)); }
/// <summary> /// Multiplies two real, rectangular matrices. /// </summary> /// <param name="A">The first matrix.</param> /// <param name="B">The second matrix.</param> /// <returns>The product matrix AB.</returns> public static RectangularMatrix operator *(RectangularMatrix A, RectangularMatrix B) { // This is faster than the base operator, because it knows about the underlying storage structure if (A == null) { throw new ArgumentNullException(nameof(A)); } if (B == null) { throw new ArgumentNullException(nameof(B)); } if (A.cols != B.rows) { throw new DimensionMismatchException(); } double[] abStore = MatrixAlgorithms.Multiply( A.store, A.offset, A.rowStride, A.colStride, B.store, B.offset, B.rowStride, B.colStride, A.rows, A.cols, B.cols ); return(new RectangularMatrix(abStore, A.rows, B.cols)); }
/// <summary> /// Returns the transpose of the matrix. /// </summary> /// <returns>M<sup>T</sup></returns> public RectangularMatrix Transpose() { double[] tStore = MatrixAlgorithms.Transpose(store, rows, cols); return(new RectangularMatrix(tStore, cols, rows)); }
/// <summary> /// Computes the inverse of the matrix. /// </summary> /// <returns>The matrix inverse M<sup>-1</sup>.</returns> /// <remarks> /// <para>The inverse of a matrix M is a matrix M<sup>-1</sup> such that M<sup>-1</sup>M = I, where I is the identity matrix.</para> /// <para>If the matrix is singular, inversion is not possible. In that case, this method will fail with a <see cref="DivideByZeroException"/>.</para> /// <para>The inversion of a matrix is an O(N<sup>3</sup>) operation.</para> /// </remarks> /// <exception cref="DivideByZeroException">The matrix is singular.</exception> public SquareMatrix Inverse() { double[] iStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); SquareMatrixAlgorithms.GaussJordanInvert(iStore, dimension); return(new SquareMatrix(iStore, dimension)); }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SquareMatrix Copy() { double[] copyStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); return(new SquareMatrix(copyStore, dimension)); }
/// <inheritdoc /> public override double OneNorm() { return(MatrixAlgorithms.OneNorm(store, offset, rowStride, colStride, dimension, dimension)); }
// EIGENVALUE ALGORITHMS // public static Complex[] ReduceToRealSchurForm(double[] aStore, double[] qStore, int dimension) { // keep track of eigenvalues Complex[] eigenvalues = new Complex[dimension]; // keep track of interations int count = 0; // isolate the upper and lower boundaries of the curent subproblem // p is the upper index, n the lower index int n = dimension - 1; while (n >= 0) { // move up the matrix from endpoint n, looking for subdiagonal elements negligible compared to the neighboring diagonal elements // if we find one, that reduces the problem to the submatrix between p and n int p = n; while (p > 0) { double d = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1)); double e = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p - 1)); if (d + e == d) { // double f = d * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p) - MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1)); // double g = e * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p)); // if (f + g == f) { MatrixAlgorithms.SetEntry(aStore, dimension, dimension, p, p - 1, 0.0); break; // } } p--; } /* * if (p == n) { * // one eigenvalue * // reduce n and re-set count * } else { * // compute m, matrix elements * // reduce n and re-set count * if (p == m) { * // two eigenvalues * } else { * // do step * } * } */ //Print(a, dimension, p, n); // get the (indexes for) the entries in the trailing 2x2 matrix int m = n - 1; int ammi = MatrixAlgorithms.GetIndex(dimension, dimension, m, m); int amni = MatrixAlgorithms.GetIndex(dimension, dimension, m, n); int anmi = MatrixAlgorithms.GetIndex(dimension, dimension, n, m); int anni = MatrixAlgorithms.GetIndex(dimension, dimension, n, n); if (n - p > 1) { count++; if (count > 32) { throw new NonconvergenceException(); } double tr = aStore[ammi] + aStore[anni]; double det = aStore[ammi] * aStore[anni] - aStore[amni] * aStore[anmi]; // ad hoc shift if ((count == 8) || (count == 16) || (count == 24)) { double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n - 1, n - 2)); tr = 2.0 * w; det = w * w; } FrancisTwoStep(aStore, qStore, dimension, p, n, tr, det); } else { if (p == n) { eigenvalues[n] = aStore[anni]; } else if (p == m) { double sn, cn; TwoByTwoRealSchur(ref aStore[ammi], ref aStore[amni], ref aStore[anmi], ref aStore[anni], out sn, out cn, out eigenvalues[m], out eigenvalues[n]); // Multiply A from left by the rotation matrix R for (int cc = p + 2; cc < dimension; cc++) { int i = MatrixAlgorithms.GetIndex(dimension, dimension, p, cc); int j = MatrixAlgorithms.GetIndex(dimension, dimension, p + 1, cc); double t = aStore[i]; aStore[i] = cn * t + sn * aStore[j]; aStore[j] = cn * aStore[j] - sn * t; } // Multiply A from the right by R^T for (int rr = 0; rr < p; rr++) { int i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p); int j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1); double t = aStore[i]; aStore[i] = cn * t + sn * aStore[j]; aStore[j] = cn * aStore[j] - sn * t; } // Multiply Q^T from the left by R if (qStore != null) { for (int rr = 0; rr < dimension; rr++) { int i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p); int j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1); double t = qStore[i]; qStore[i] = cn * t + sn * qStore[j]; qStore[j] = cn * qStore[j] - sn * t; } } } n = p - 1; count = 0; } } return(eigenvalues); }
// simple specific operations /// <summary> /// Copies the matrix. /// </summary> /// <returns>An indpendent copy of the matrix.</returns> public RectangularMatrix Copy() { double[] cStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, rows, cols); return(new RectangularMatrix(cStore, rows, cols)); }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SquareMatrix Copy() { double[] cStore = MatrixAlgorithms.Copy(store, dimension, dimension); return(new SquareMatrix(cStore, dimension)); }
/// <inheritdoc /> public override double InfinityNorm() { return(MatrixAlgorithms.InfinityNorm(store, 0, 1, dimension, dimension, dimension)); }
/// <inheritdoc /> public override double OneNorm() { return(MatrixAlgorithms.OneNorm(store, 0, 1, dimension, dimension, dimension)); }
public static void SchurEigensystem(double[] aStore, int n, out Complex[] eigenvalues, out Complex[][] eigenvectors) { eigenvalues = new Complex[n]; eigenvectors = new Complex[n][]; int i = n - 1; while (i >= 0) { // find the eigenvector corresponding to the ith eigenvalue if ((i == 0) || (MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1) == 0.0)) { // We have no sub-diagonal element on the ith row. Since // (XXXXX) ( X ) ( X ) // (XXXXX) ( X ) ( X ) // ( aXX) ( 1 ) = ( a ) // ( XX) ( 0 ) ( 0 ) // ( XX) ( 0 ) ( 0 ) // a vector with v[i] = 1, v[j > i] = 0, and v[j < i] properly chosen will be an eigenvector. // the eigenvalue is the ith diagonal element double e = MatrixAlgorithms.GetEntry(aStore, n, n, i, i); // we take the ith component of the eigenvector to be one; higher components must be zero Complex[] v = new Complex[n]; v[i] = 1.0; CompleteEigenvector(aStore, n, v, e, i, i - 1); //WriteTransformedEigenvector(i, e, v, n, Q); eigenvectors[i] = v; eigenvalues[i] = e; i--; } else { // We have a 2x2 sub-block // ( X X X ) // ( [X X]) // ( [X X]) // Find its eigenvalues Complex e1, e2; TwoByTwoEigenvalues( MatrixAlgorithms.GetEntry(aStore, n, n, i - 1, i - 1), MatrixAlgorithms.GetEntry(aStore, n, n, i - 1, i), MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1), MatrixAlgorithms.GetEntry(aStore, n, n, i, i), out e1, out e2 ); //TwoByTwoEigenvalues(a[i - 1, i - 1], a[i - 1, i], a[i, i - 1], a[i, i], out e1, out e2); // For each eigenvalue, compute the trailing eigenvector components and then the remaining components. // For the trailing components, since // (a11 a12) ( v1 ) = \lambda ( v1 ) // (a21 a22) ( v2 ) ( v2 ) // It follows that // v1 = (\lambda - a22) / a21 * v2 // and we normalize by choosing v2 = 1. Since we are only here if a21 != 0, there is no danger of // dividing by zero, but there may well be a danger that (\lambda - a22) looses significant // precision due to cancelation. Complex[] v = new Complex[n]; v[i] = 1.0; //v[i - 1] = (e1 - a[i, i]) / a[i, i - 1]; v[i - 1] = (e1 - MatrixAlgorithms.GetEntry(aStore, n, n, i, i)) / MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1); CompleteEigenvector(aStore, n, v, e1, i, i - 2); //WriteTransformedEigenvector(i, e1, v, n, Q); eigenvectors[i] = v; eigenvalues[i] = e1; v = new Complex[n]; v[i] = 1.0; //v[i - 1] = (e2 - a[i, i]) / a[i, i - 1]; v[i - 1] = (e2 - MatrixAlgorithms.GetEntry(aStore, n, n, i, i)) / MatrixAlgorithms.GetEntry(aStore, n, n, i, i - 1); CompleteEigenvector(aStore, n, v, e2, i, i - 2); //WriteTransformedEigenvector(i - 1, e2, v, n, Q); eigenvectors[i - 1] = v; eigenvalues[i - 1] = e2; i -= 2; } } }
// inverts the matrix in place // the in-place-ness makes this a bit confusing public static void GaussJordanInvert(double[] store, int dimension) { // keep track of row exchanges int[] ps = new int[dimension]; // iterate over dimensions for (int k = 0; k < dimension; k++) { // look for a pivot in the kth column on any lower row int p = k; double q = MatrixAlgorithms.GetEntry(store, dimension, dimension, k, k); for (int r = k + 1; r < dimension; r++) { double s = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k); if (Math.Abs(s) > Math.Abs(q)) { p = r; q = s; } } ps[k] = p; // if no non-zero pivot is found, the matrix is singular and cannot be inverted if (q == 0.0) { throw new DivideByZeroException(); } // if the best pivot was on a lower row, swap it into the kth row if (p != k) { Blas1.dSwap(store, k, dimension, store, p, dimension, dimension); } // divide the pivot row by the pivot element, so the diagonal element becomes unity MatrixAlgorithms.SetEntry(store, dimension, dimension, k, k, 1.0); Blas1.dScal(1.0 / q, store, k, dimension, dimension); // add factors to the pivot row to zero all off-diagonal elements in the kth column for (int r = 0; r < dimension; r++) { if (r == k) { continue; } double a = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k); MatrixAlgorithms.SetEntry(store, dimension, dimension, r, k, 0.0); Blas1.dAxpy(-a, store, k, dimension, store, r, dimension, dimension); } } // unscramble exchanges for (int k = dimension - 1; k >= 0; k--) { int p = ps[k]; if (p != k) { Blas1.dSwap(store, dimension * p, 1, store, dimension * k, 1, dimension); } } }
public static Complex[] ExtractEigenvalues(double[] aStore, double[] qStore, int dimension) { int count = 0; // keep track of extracted eigenvalues Complex[] lambdas = new Complex[dimension]; double sum_old = Double.PositiveInfinity; int n = dimension - 1; while (n >= 0) { //Write(aStore, dimension, dimension); // find the lowest decoupled, unreduced block int a = n; double sum = 0.0; while (a > 0) { double f = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a - 1, a - 1)); double e = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a - 1); if ((f + e) == f) { MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a - 1, 0.0); break; } sum += Math.Abs(e); a--; } /* * Console.WriteLine("count = {0}", count); * double[] qt = MatrixAlgorithms.Transpose(qStore, dimension, dimension); * double[] qa = MatrixAlgorithms.Multiply(qStore, dimension, dimension, aStore, dimension, dimension); * double[] qaqt = MatrixAlgorithms.Multiply(qa, dimension, dimension, qt, dimension, dimension); * MatrixAlgorithms.PrintMatrix(qaqt, dimension, dimension); */ // check for maximum numbers of iterations without finding an eigenvalue if (count > 32) { throw new NonconvergenceException(); } // we are working between a and n, and our block is at least 3 wide // reduce if possible, otherwise do a iteration step if (a == n) { // 1 X 1 block isolated lambdas[a] = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a); n -= 1; count = 0; sum_old = Double.PositiveInfinity; } else if (a == (n - 1)) { // 2 X 2 block isolated double Aaa = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a); double Aba = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a); double Aab = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a + 1); double Abb = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a + 1); // eigenvalues are given by the quadratic formula // e = \frac{a_11 + a22}{2} \pm q // descriminant q^2 = ( \frac{a_11 - a_22}{2} )^2 + a_21 a_1 double c = (Aaa + Abb) / 2.0; double d = Aaa * Abb - Aba * Aab; double q2 = c * c - d; if (q2 >= 0.0) { // eigenvalues are real double q = Math.Sqrt(q2); if (c >= 0.0) { lambdas[a] = c + q; } else { lambdas[a] = c - q; } // i tried to do this as c + Math.Sign(c) * q, but when c = 0, Math.Sign(c) = 0, not 1 lambdas[a + 1] = d / lambdas[a]; /* * double sn, cn; * TwoByTwoSchur(ref Aaa, ref Aab, ref Aba, ref Abb, out sn, out cn); * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a, Aaa); * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a + 1, Aab); * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a, Aba); * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a + 1, Abb); * * // Multiply A from left by the rotation matrix R * for (int cc = a + 2; cc < dimension; cc++) { * int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc); * int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc); * double t = aStore[i]; * aStore[i] = cn * t + sn * aStore[j]; * aStore[j] = cn * aStore[j] - sn * t; * } * // Multiply A from the right by R^T * for (int rr = 0; rr < a; rr++) { * int i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a); * int j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a + 1); * double t = aStore[i]; * aStore[i] = cn * t + sn * aStore[j]; * aStore[j] = cn * aStore[j] - sn * t; * } * // Multiply Q^T from the left by R * if (qStore != null) { * for (int cc = 0; cc < dimension; cc++) { * int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc); * int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc); * double t = qStore[i]; * qStore[i] = cn * t + sn * qStore[j]; * qStore[j] = cn * qStore[j] - sn * t; * } * } * * lambdas[a] = Aaa; * lambdas[a + 1] = Abb; */ } else { double q = Math.Sqrt(-q2); lambdas[a] = new Complex(c, q); lambdas[a + 1] = new Complex(c, -q); } n -= 2; count = 0; sum_old = Double.PositiveInfinity; } else { // use the lower-left 2 X 2 matrix to generate an approximate eigenvalue pair int m = n - 1; double Amm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m); double Amn = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, n); double Anm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, m); double Ann = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n); // the trace of this 2 X 2 matrix is the sum of its eigenvalues, and its determinate is their product double tr = Amm + Ann; double det = Amm * Ann - Amn * Anm; // ad hoc shift if ((count == 8) || (count == 16) || (count == 24)) { double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m - 1)); tr = 2.0 * w; det = w * w; } FrancisTwoStep(aStore, qStore, dimension, a, n, tr, det); sum_old = sum; count++; } } return(lambdas); }
/// <inheritdoc /> public override double InfinityNorm() { return(MatrixAlgorithms.InfinityNorm(store, offset, rowStride, colStride, rows, cols)); }
/* * IMatrix IMatrix.Clone () { * return (Clone()); * } */ /// <summary> /// Creates a transpose of the matrix. /// </summary> /// <returns>The matrix transpose M<sup>T</sup>.</returns> public SquareMatrix Transpose() { double[] tStore = MatrixAlgorithms.Transpose(store, dimension, dimension); return(new SquareMatrix(tStore, dimension)); }
/// <summary> /// The orthogonal matrix Q. /// </summary> /// <returns>The orthogonal matrix Q.</returns> public SquareMatrix QMatrix() { double[] qStore = MatrixAlgorithms.Transpose(qtStore, dimension, dimension); return(new SquareMatrix(qStore, dimension)); }
/// <summary> /// Returns the transpose of the matrix. /// </summary> /// <returns>M<sup>T</sup></returns> public RectangularMatrix Transpose() { // Just copy with rows <-> columns to get transpose double[] transpose = MatrixAlgorithms.Copy(store, offset, colStride, rowStride, cols, rows); return(new RectangularMatrix(transpose, cols, rows)); }
/// <summary> /// Returns the left transform matrix. /// </summary> /// <returns>The matrix U, such that A = U S V<sup>T</sup>.</returns> public SquareMatrix LeftTransformMatrix() { double[] left = MatrixAlgorithms.Transpose(utStore, rows, rows); return(new SquareMatrix(left, rows)); }