private static double[] GenerateFirstColumn(double[] aStore, int dimension, int a, int n, double sum, double product) { // compute the first column of M = (A - \lambda I) (A - \lambda^* I) = A^2 - 2 Re(\lambda) + |\lambda|^2 I // where 2 Re(\lambda) = sum of approximate eigenvalues, |\lambda|^2 = product of approximate eigenvalues // since A is Hessenberg, this has only three entries // first get the relevant A entries, which for the first column are from the leading Hesenberg entries int b = a + 1; int c = a + 2; double Aaa = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a); double Aab = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, b); double Aba = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, b, a); double Abb = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, b, b); double Acb = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, c, b); // Aba should not be zero, or the problem would have been reduced Debug.Assert(Aba != 0.0); // use these entries and the sum and product of eigenvalues of get first column double[] u = new double[3]; u[0] = Aaa * (Aaa - sum) + Aba * Aab + product; u[1] = Aba * (Aaa + Abb - sum); u[2] = Aba * Acb; return(u); }
/// <summary> /// Gets or sets an entry of the matrix. /// </summary> /// <param name="r">The (zero-based) row number.</param> /// <param name="c">The (zero-based) column number.</param> /// <returns>The value of the specified matrix entry M<sub>r c</sub>.</returns> public override double this[int r, int c] { get { if ((r < 0) || (r >= dimension)) { throw new ArgumentOutOfRangeException("r"); } if ((c < 0) || (c >= dimension)) { throw new ArgumentOutOfRangeException("c"); } return(MatrixAlgorithms.GetEntry(store, dimension, dimension, r, c)); } set { if ((r < 0) || (r >= dimension)) { throw new ArgumentOutOfRangeException("r"); } if ((c < 0) || (c >= dimension)) { throw new ArgumentOutOfRangeException("c"); } if (IsReadOnly) { throw new InvalidOperationException(); } MatrixAlgorithms.SetEntry(store, dimension, dimension, r, c, value); } }
/// <summary> /// Computes the determinant of the original matrix. /// </summary> /// <returns>det A</returns> public double Determinant() { double det = 1.0; for (int i = 0; i < dimension; i++) { det *= MatrixAlgorithms.GetEntry(rStore, dimension, dimension, i, i); } return(det); }
// v is assumed to private static void CompleteEigenvector(double[] aStore, int n, Complex[] v, Complex e, int i, int j) { while (j >= 0) { if ((j == 0) || (MatrixAlgorithms.GetEntry(aStore, n, n, j, j - 1) == 0.0)) { Complex t = 0.0; for (int k = j + 1; k <= i; k++) { t += MatrixAlgorithms.GetEntry(aStore, n, n, j, k) * v[k]; //t += a[j, k] * v[k]; } if (t == 0.0) { // this branch exists to avoid undefined 0.0 / 0.0 v[j] = 0.0; } else { //v[j] = t / (e - a[j, j]); v[j] = t / (e - MatrixAlgorithms.GetEntry(aStore, n, n, j, j)); } j--; } else { Complex t1 = 0.0; Complex t2 = 0.0; for (int k = j + 1; k <= i; k++) { t1 -= MatrixAlgorithms.GetEntry(aStore, n, n, j - 1, k) * v[k]; t2 -= MatrixAlgorithms.GetEntry(aStore, n, n, j, k) * v[k]; //t1 -= a[j - 1, k] * v[k]; //t2 -= a[j, k] * v[k]; } TwoByTwoSystem( MatrixAlgorithms.GetEntry(aStore, n, n, j - 1, j - 1) - e, MatrixAlgorithms.GetEntry(aStore, n, n, j - 1, j), MatrixAlgorithms.GetEntry(aStore, n, n, j, j - 1), MatrixAlgorithms.GetEntry(aStore, n, n, j, j) - e, ref t1, ref t2 ); //TwoByTwoSystem(a[j - 1, j - 1] - e, a[j - 1, j], a[j, j - 1], a[j, j] - e, ref t1, ref t2); v[j - 1] = t1; v[j] = t2; j -= 2; } } }
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); }
// 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); }