/** * Transforms the matrix to Schur form and calculates the eigenvalues. * * @param matrix Matrix to transform. * @return the {@link SchurTransformer Shur transform} for this matrix */ private SchurTransformer transformToSchur(RealMatrix matrix) { SchurTransformer schurTransform = new SchurTransformer(matrix); double[][] matT = schurTransform.getT().getData(); realEigenvalues = new double[matT.Length]; imagEigenvalues = new double[matT.Length]; for (int i = 0; i < realEigenvalues.Length; i++) { if (i == (realEigenvalues.Length - 1) || Precision.equals(matT[i + 1][i], 0.0, EPSILON)) { realEigenvalues[i] = matT[i][i]; } else { double x = matT[i + 1][i + 1]; double p = 0.5 * (matT[i][i] - x); double z = Math.Sqrt(Math.Abs(p * p + matT[i + 1][i] * matT[i][i + 1])); realEigenvalues[i] = x + p; imagEigenvalues[i] = z; realEigenvalues[i + 1] = x + p; imagEigenvalues[i + 1] = -z; i++; } } return(schurTransform); }
/** * Calculates the eigen decomposition of the given real matrix. * <p> * Supports decomposition of a general matrix since 3.1. * * @param matrix Matrix to decompose. * @throws MaxCountExceededException if the algorithm fails to converge. * @throws MathArithmeticException if the decomposition of a general matrix * results in a matrix with zero norm * @since 3.1 */ public EigenDecomposition(RealMatrix matrix) { double symTol = 10 * matrix.getRowDimension() * matrix.getColumnDimension() * Precision.EPSILON; isSymmetric = MatrixUtils.IsSymmetric(matrix, symTol); if (isSymmetric) { transformToTridiagonal(matrix); findEigenVectors(transformer.getQ().getData()); findEigenVectors(transformer.getQ().getData()); } else { SchurTransformer t = transformToSchur(matrix); findEigenVectorsFromSchur(t); } }
/** * Find eigenvectors from a matrix transformed to Schur form. * * @param schur the schur transformation of the matrix * @throws MathArithmeticException if the Schur form has a norm of zero */ private void findEigenVectorsFromSchur(SchurTransformer schur) { double[][] matrixT = schur.getT().getData(); double[][] matrixP = schur.getP().getData(); int n = matrixT.Length; // compute matrix norm double norm = 0.0; for (int i = 0; i < n; i++) { for (int j = Math.Max(i - 1, 0); j < n; j++) { norm += Math.Abs(matrixT[i][j]); } } // we can not handle a matrix with zero norm if (Precision.equals(norm, 0.0, EPSILON)) { throw new Exception("MathArithmeticException"); } // Backsubstitute to find vectors of upper triangular form double r = 0.0; double s = 0.0; double z = 0.0; for (int idx = n - 1; idx >= 0; idx--) { double p = realEigenvalues[idx]; double q = imagEigenvalues[idx]; if (Precision.equals(q, 0.0)) { // Real vector int l = idx; matrixT[idx][idx] = 1.0; for (int i = idx - 1; i >= 0; i--) { double w = matrixT[i][i] - p; r = 0.0; for (int j = l; j <= idx; j++) { r += matrixT[i][j] * matrixT[j][idx]; } if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0) { z = w; s = r; } else { l = i; if (Precision.equals(imagEigenvalues[i], 0.0)) { if (w != 0.0) { matrixT[i][idx] = -r / w; } else { matrixT[i][idx] = -r / (Precision.EPSILON * norm); } } else { // Solve real equations double x = matrixT[i][i + 1]; double y = matrixT[i + 1][i]; q = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) + imagEigenvalues[i] * imagEigenvalues[i]; double t = (x * s - z * r) / q; matrixT[i][idx] = t; if (Math.Abs(x) > Math.Abs(z)) { matrixT[i + 1][idx] = (-r - w * t) / x; } else { matrixT[i + 1][idx] = (-s - y * t) / z; } } // Overflow control double tx = Math.Abs(matrixT[i][idx]); if ((Precision.EPSILON * tx) * tx > 1) { for (int j = i; j <= idx; j++) { matrixT[j][idx] /= tx; } } } } } else if (q < 0.0) { // Complex vector int l = idx - 1; // Last vector component imaginary so matrix is triangular if (Math.Abs(matrixT[idx][idx - 1]) > Math.Abs(matrixT[idx - 1][idx])) { matrixT[idx - 1][idx - 1] = q / matrixT[idx][idx - 1]; matrixT[idx - 1][idx] = -(matrixT[idx][idx] - p) / matrixT[idx][idx - 1]; } else { Complex result = cdiv(0.0, -matrixT[idx - 1][idx], matrixT[idx - 1][idx - 1] - p, q); matrixT[idx - 1][idx - 1] = result.getReal(); matrixT[idx - 1][idx] = result.getImaginary(); } matrixT[idx][idx - 1] = 0.0; matrixT[idx][idx] = 1.0; for (int i = idx - 2; i >= 0; i--) { double ra = 0.0; double sa = 0.0; for (int j = l; j <= idx; j++) { ra += matrixT[i][j] * matrixT[j][idx - 1]; sa += matrixT[i][j] * matrixT[j][idx]; } double w = matrixT[i][i] - p; if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0) { z = w; r = ra; s = sa; } else { l = i; if (Precision.equals(imagEigenvalues[i], 0.0)) { Complex c = cdiv(-ra, -sa, w, q); matrixT[i][idx - 1] = c.getReal(); matrixT[i][idx] = c.getImaginary(); } else { // Solve complex equations double x = matrixT[i][i + 1]; double y = matrixT[i + 1][i]; double vr = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) + imagEigenvalues[i] * imagEigenvalues[i] - q * q; double vi = (realEigenvalues[i] - p) * 2.0 * q; if (Precision.equals(vr, 0.0) && Precision.equals(vi, 0.0)) { vr = Precision.EPSILON * norm * (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z)); } Complex c = cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi); matrixT[i][idx - 1] = c.getReal(); matrixT[i][idx] = c.getImaginary(); if (Math.Abs(x) > (Math.Abs(z) + Math.Abs(q))) { matrixT[i + 1][idx - 1] = (-ra - w * matrixT[i][idx - 1] + q * matrixT[i][idx]) / x; matrixT[i + 1][idx] = (-sa - w * matrixT[i][idx] - q * matrixT[i][idx - 1]) / x; } else { Complex c2 = cdiv(-r - y * matrixT[i][idx - 1], -s - y * matrixT[i][idx], z, q); matrixT[i + 1][idx - 1] = c2.getReal(); matrixT[i + 1][idx] = c2.getImaginary(); } } // Overflow control double t = Math.Max(Math.Abs(matrixT[i][idx - 1]), Math.Abs(matrixT[i][idx])); if ((Precision.EPSILON * t) * t > 1) { for (int j = i; j <= idx; j++) { matrixT[j][idx - 1] /= t; matrixT[j][idx] /= t; } } } } } } // Back transformation to get eigenvectors of original matrix for (int j = n - 1; j >= 0; j--) { for (int i = 0; i <= n - 1; i++) { z = 0.0; for (int k = 0; k <= Math.Min(j, n - 1); k++) { z += matrixP[i][k] * matrixT[k][j]; } matrixP[i][j] = z; } } eigenvectors = new ArrayRealVector[n]; double[] tmp = new double[n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { tmp[j] = matrixP[j][i]; } eigenvectors[i] = new ArrayRealVector(tmp); } }