/** @file jacobi.cpp * @brief Implementation of the jacobi rotation method * * @author Cory Alexander Balaton (coryab) * @author Janita Ovidie Sandtrøen Willumsen (janitaws) * @bug The eigenvalues fail the test. When comparing them to arma::eigsym * there is one value that is way off when testing with a 6x6 matrix. */ #include #include #include #include "utils.hpp" #include "jacobi.hpp" #include "matrix.hpp" void jacobi_rotate(arma::mat& A, arma::mat& R, int k, int l) { double tau, t, c, s, sr, a_kk, a_ik, r_ik; tau = (A(l,l) - A(k,k))/(2.*A(k,l)); sr = sqrt(1 + tau*tau); t = - tau + (tau > 0. ? sr : -sr); c = 1. / std::sqrt(1. + t*t); s = c*t; // Calculating the diagonal elements at index k an l a_kk = A(k,k); A(k,k) = a_kk*c*c - 2.*A(k,l)*c*s + A(l,l)*s*s; A(l,l) = A(l,l)*c*c + 2.*A(k,l)*c*s + a_kk*s*s; A(k,l) = A(l,k) = 0.; // These are 0 by definition // Calculating the other values on rows/cols k and l of A for (int i=0; i < A.n_rows; i++) { if (i == k || i == l) { continue; } a_ik = A(i,k); A(i,k) = a_ik*c - A(i,l)*s; A(k,i) = A(i,k); A(i,l) = A(i,l)*c + a_ik*s; A(l,i) = A(i,l); } // Calculate the values for R for (int i=0; i < R.n_rows; i++) { r_ik = R(i,k); R(i,k) = r_ik*c - R(i,l)*s; R(i,l) = R(i,l)*c + r_ik*s; } } void jacobi_eigensolver(const arma::mat& A, double eps, arma::vec& eigenvalues, arma::mat& eigenvectors, const int maxiter, int& iterations, bool& converged) { int k, l; double max_offdiag; // Initialize matrices arma::mat A_m = A; arma::mat R = arma::mat(A.n_rows, A.n_cols, arma::fill::eye); iterations = 0; // Use a do while so that max_offdiag gets a value before doing a comparison do { max_offdiag = max_offdiag_symmetric(A_m, k, l); jacobi_rotate(A_m, R, k, l); } while (max_offdiag >= eps && ++iterations < maxiter); // Get the diagonal of A arma::vec res = arma::diagvec(A_m); // Get the indeces of res in sorted order arma::uvec sorted_indeces = arma::sort_index(res); eigenvalues.resize(res.n_elem); eigenvectors.resize(res.n_elem, res.n_elem); // Set the eigenvalues and their corresponding vectors in order for (int i=0; i < res.n_elem; i++) { eigenvalues[i] = res[sorted_indeces[i]]; eigenvectors.insert_cols(i, R.col(sorted_indeces[i])); } converged = max_offdiag < eps; }