/** * Only eigenvalues of a symmetric real matrix are computed. * * @param A a symmetric real matrix * @return a 1D {@code double} array containing the eigenvalues in decreasing order (absolute * value) */ public static double[] computeEigenvalues(Matrix A) { SparseMatrix S = (SparseMatrix) decompose(A, false)[1]; int m = S.getRowDimension(); int n = S.getColumnDimension(); int len = m >= n ? n : m; double[] s = ArrayOperator.allocateVector(len, 0); for (int i = 0; i < len; i++) { s[i] = S.getEntry(i, i); } return s; }
/** * Do eigenvalue decomposition for a real symmetric tridiagonal matrix, i.e. T = VDV'. * * @param T a real symmetric tridiagonal matrix * @param computeV if V is to be computed * @return a {@code Matrix} array [V, D] */ private static Matrix[] diagonalizeTD(Matrix T, boolean computeV) { int m = T.getRowDimension(); int n = T.getColumnDimension(); int len = m >= n ? n : m; int idx = 0; /* * The tridiagonal matrix T is * s[0] e[0] * e[0] s[1] e[1] * e[1] ... * s[len - 2] e[len - 2] * e[len - 2] s[len - 1] */ double[] s = ArrayOperator.allocateVector(len, 0); double[] e = ArrayOperator.allocateVector(len, 0); for (int i = 0; i < len - 1; i++) { s[i] = T.getEntry(i, i); e[i] = T.getEntry(i, i + 1); } s[len - 1] = T.getEntry(len - 1, len - 1); // V': each row of V' is a right singular vector double[][] Vt = null; if (computeV) Vt = eye(n, n).getData(); double[] mu = ArrayOperator.allocate1DArray(len, 0); /* * T0 = ITI', V = I * T = IT0I' = VT0G1G1'Vt = VT0G1(G1'Vt) * = VG1G1'T0G1(G1'Vt) = (VG1)(G1'T0G1)(G1'Vt) * = (VG1)T1(G1'Vt) * ... * = (Gn-1...G2G1)D(G1G2...Gn-1)' * * where G = |cs sn| * |-sn cs| * G' = |cs -sn| * |sn cs| */ /* * Find B_hat, i.e. the bottommost unreduced submatrix of B. * Index starts from 0. */ // ********************************************************* int i_start = 0; int i_end = len - 1; // int cnt_shifted = 0; int ind = 1; while (true) { idx = len - 2; while (idx >= 0) { if (e[idx] == 0) { idx--; } else { break; } } i_end = idx + 1; // Now idx = -1 or e[idx] != 0 // If idx = -1, then e[0] = 0, i_start = i_end = 0, e = 0 // Else if e[idx] != 0, then e[i] = 0 for i_end = idx + 1 <= i <= len - 1 while (idx >= 0) { if (e[idx] != 0) { idx--; } else { break; } } i_start = idx + 1; // Now idx = -1 or e[idx] = 0 // If idx = -1 i_start = 0 // Else if e[idx] = 0, then e[idx + 1] != 0, e[i_end - 1] != 0 // i.e. e[i] != 0 for i_start <= i <= i_end - 1 if (i_start == i_end) { break; } // Apply the stopping criterion to B_hat // If any e[i] is set to zero, return to loop boolean set2Zero = false; mu[i_start] = abs(s[i_start]); for (int j = i_start; j < i_end; j++) { mu[j + 1] = abs(s[j + 1]) * mu[j] / (mu[j] + abs(e[j])); if (abs(e[j]) <= mu[j] * tol) { e[j] = 0; set2Zero = true; } } if (set2Zero) { continue; } implicitSymmetricShiftedQR(s, e, Vt, i_start, i_end, computeV); // cnt_shifted++; if (ind == maxIter) { break; } ind++; } // fprintf("cnt_shifted: %d\n", cnt_shifted); // ********************************************************* // Quick sort eigenvalues and eigenvectors quickSort(s, Vt, 0, len - 1, "descend", computeV); Matrix[] VD = new Matrix[2]; VD[0] = computeV ? new DenseMatrix(Vt).transpose() : null; VD[1] = buildD(s, m, n); /*disp("T:"); printMatrix(T); disp("VDV':"); Matrix V = VD[0]; Matrix D = VD[1]; disp(V.mtimes(D).mtimes(V.transpose()));*/ return VD; }
/** * Tridiagonalize a real symmetric matrix A, i.e. A = Q * T * Q' such that Q is an orthogonal * matrix and T is a tridiagonal matrix. * * <p>A = QTQ' <=> Q'AQ = T * * @param A a real symmetric matrix * @param computeV if V is to be computed * @return a {@code Matrix} array [Q, T] */ private static Matrix[] tridiagonalize(Matrix A, boolean computeV) { A = full(A).copy(); int m = A.getRowDimension(); int n = A.getColumnDimension(); Matrix[] QT = new Matrix[2]; double[] a = ArrayOperator.allocateVector(n, 0); double[] b = ArrayOperator.allocateVector(n, 0); double[][] AData = ((DenseMatrix) A).getData(); double c = 0; double s = 0; double r = 0; for (int j = 0; j < n - 2; j++) { a[j] = AData[j][j]; // Householder transformation on columns of A(j+1:m, j+1:n) // Compute the norm of A(j+1:m, j) c = 0; for (int i = j + 1; i < m; i++) { c += Math.pow(AData[i][j], 2); } if (c == 0) continue; s = Math.sqrt(c); b[j] = AData[j + 1][j] > 0 ? -s : s; r = Math.sqrt(s * (s + abs(AData[j + 1][j]))); /*double[] u1 = ArrayOperation.allocate1DArray(n, 0); for (int k = j + 1; k < m; k++) { u1[k] = AData[k][j]; } u1[j + 1] -= b[j]; for (int k = j + 1; k < m; k++) { u1[k] /= r; } Matrix H = eye(n).minus(new DenseMatrix(u1, 1).mtimes(new DenseMatrix(u1, 2))); disp(new DenseMatrix(u1, 1)); disp(eye(n)); disp(H); disp(A); disp(H.mtimes(A).mtimes(H)); disp(A);*/ AData[j + 1][j] -= b[j]; for (int k = j + 1; k < m; k++) { AData[k][j] /= r; } double[] w = new double[n - j - 1]; double[] u = new double[n - j - 1]; double[] v = new double[n - j - 1]; for (int i = j + 1, t = 0; i < m; i++, t++) { u[t] = AData[i][j]; } // v = B33 * u for (int i = j + 1, t = 0; i < m; i++, t++) { double[] ARow_i = AData[i]; s = 0; for (int k = j + 1, l = 0; k < n; k++, l++) { s += ARow_i[k] * u[l]; } v[t] = s; } c = ArrayOperator.innerProduct(u, v) / 2; for (int i = j + 1, t = 0; i < m; i++, t++) { w[t] = v[t] - c * u[t]; } /*disp(w); Matrix B33 = new DenseMatrix(n - j - 1, n - j - 1, 0); for (int i = j + 1, t = 0; i < m; i++, t++) { double[] ARow_i = AData[i]; for (int k = j + 1, l = 0; k < n; k++, l++) { B33.setEntry(t, l, ARow_i[k]); } } disp(B33); Matrix U = new DenseMatrix(u, 1); disp(U.transpose().mtimes(U)); disp(U); Matrix W = B33.mtimes(U).minus(U); disp(W); disp(B33.minus(plus(U.mtimes(W.transpose()), W.mtimes(U.transpose())))); Matrix Hk = eye(n - j - 1).minus(U.mtimes(U.transpose())); disp(Hk); disp(Hk.mtimes(B33).mtimes(Hk));*/ for (int i = j + 1, t = 0; i < m; i++, t++) { double[] ARow_i = AData[i]; for (int k = j + 1, l = 0; k < n; k++, l++) { ARow_i[k] = ARow_i[k] - (u[t] * w[l] + w[t] * u[l]); } } // disp(A); /*fprintf("Householder transformation on n - 1 columns:\n"); disp(A);*/ // disp(A); // Householder transformation on rows of A(j:m, j+1:n) } a[n - 2] = AData[n - 2][n - 2]; a[n - 1] = AData[n - 1][n - 1]; b[n - 2] = AData[n - 1][n - 2]; QT = unpack(A, a, b, computeV); return QT; }