Program Listing for File sparseSolver.hpp

Return to documentation for file (utils/sparseSolver.hpp)

#pragma once
#include "functions.hpp"
#include "qmatrix.hpp"
#include "timer.hpp"
#include <algorithm>
#include <cstddef>
#define EIGEN_USE_MKL_ALL
#include <eigen3/Eigen/Sparse>
#include <iostream>
#include <vector>
// Spcetra
#include <Spectra/GenEigsRealShiftSolver.h>
#include <Spectra/MatOp/SparseGenRealShiftSolve.h>
class exactSolver {
  qmatrix<double> qmat;
  size_t          column;

public:
  explicit exactSolver(size_t n = 0) : column(n) { qmat.resize(n, n, 0); }
  void set(size_t i, size_t j, double val) {
    qmat(i, j) = qmat(i, j) + val; // +=
  }
  std::vector<double> solve() {
    // std::cout << "Solving exact" << std::endl;
    // auto [leftVec, rightVec, eig] = qmat.nonsys_diag_real();
    // Clang complains about this line, but it works.
    // auto [leftVec, rightVec, eig] = qmat.nonsys_diag_real();
    auto                diagSolver = qmat.nonsys_diag_real();
    auto                leftVec    = std::get<0>(diagSolver);
    auto                rightVec   = std::get<1>(diagSolver);
    auto                eig        = std::get<2>(diagSolver);
    std::vector<double> X(column, {0});
    double              trace = 0;
    size_t              idx   = minIndex(eig); // index of minimum value
#pragma omp parallel for reduction(+ : trace)
    for (size_t i = 0; i < column; i++) {
      // std::cout << "Left Eigen vaector " << leftVec(i, idx) << std::endl;
      X[i] = rightVec(i, idx).real();
      trace += X[i];
    }
    std::cout << "EigenValue" << eig[idx] << " trace :" << trace << std::endl;
    // std::cout << "Evec:" << X << std::endl;
    // trace should be one
    // parallelization
    std::transform(
        // std::execution::par_unseq,
        X.begin(), X.end(), X.begin(), [trace](double x) { return x / trace; });
    return X;
  }
  auto vectorDot(std::vector<double> &a) {
    // std::cout << "Started vectorDot" << std::endl;
    auto tmMat = qmat.dot(qmatrix<double>(a, column, 1));
    // std::cout << "End of vectorDot" << std::endl;
    return std::vector<double>(tmMat.begin(), tmMat.end());
  }
};
/*
class sparseArma {
  arma::sp_mat sparseMat;
  size_t       column; // Assumes that the row = column
public:
  sparseArma(size_t n = 0) {
    column    = n;
    sparseMat = arma::sp_mat(n, n);
  }
  void set(size_t i, size_t j, double val) { sparseMat(j, i) = val; }
  auto getMatrix() { return sparseMat; }
  auto solve() {
    arma::cx_vec    eigval;
    arma::cx_mat    eigvec;
    arma::eigs_opts opts;
    opts.maxiter = 10000; // increase max iterations to 10000
    eigs_gen(eigval, eigvec, sparseMat, 1, 1e-8, opts);
    std::vector<double> X(column, {0});
    double              trace = 0;
    for (size_t i = 0; i < column; i++) {
      X[i] = eigvec(i, 0).real();
      trace += X[i];
    }
    // trace should be one
    for (auto &aa : X) {
      aa = aa / trace;
    }
    std::cout << "Eigenvalues: " << eigval << " trace " << trace << std::endl;
    return X;
  }
  auto vectorDot(const std::vector<double> &X) {
    std::cout << "Started vectorDot" << std::endl;
    auto result = arma::vec(sparseMat * arma::vec(X));
    std::cout << "Type: " << typeid(result).name() << std::endl;
    std::cout << "Endend vectorDot" << std::endl;
    return result;
  }
};

*/
class sparseEigen {
  using datatype = double;
  std::vector<Eigen::Triplet<datatype>>
                                coefficients; // coefficients of the matrix
  size_t                        column;
  Eigen::SparseMatrix<datatype> SparseA;

public:
  explicit sparseEigen(size_t n = 0)
      : column(n), SparseA(Eigen::SparseMatrix<datatype>(n, n)) {
    // column = n; // Assumes that the row = column
  }
  void set(size_t i, size_t j, double value) {
    coefficients.emplace_back(i, j, value);
  }
  auto getMatrix() {
    SparseA.setFromTriplets(coefficients.begin(), coefficients.end());
    return SparseA;
  }
  auto solve() {
    // set the matrix
    SparseA.setFromTriplets(coefficients.begin(), coefficients.end());
    // Setup solver
    // Spectra::SparseGenMatProd<datatype> op(SparseA);
    // Spectra::GenEigsSolver              eigs(op, 1, column / 2);
    Spectra::SparseGenRealShiftSolve<double> op(SparseA);
    Spectra::GenEigsRealShiftSolver          eigs(op, 1, column / 2,
                                                  1e-6); // Initialize and compute
    eigs.init();
    eigs.compute(
        Spectra::SortRule::LargestMagn); // returns the smallest eigenvalues
    // std::cout << "ncov : " << nconv << std::endl;
    // Retrieve results
    std::vector<double> X(column, {0});
    if (eigs.info() == Spectra::CompInfo::Successful) {
      double           rhoTrace = 0.0;
      Eigen::VectorXcd evalues  = eigs.eigenvalues();
      auto             eigVec   = eigs.eigenvectors(); // This change this shit
      // std::cout<< "evalues : " <<  eigVec.size() <<" "<< column<< std::endl;
      for (size_t i = 0; i < column; i++) {
        X[i]     = eigVec(i, 0).real();
        rhoTrace = rhoTrace + X[i];
      }
      // trace should be one
      for (auto &aa : X) {
        aa = aa / rhoTrace;
      }
      std::cout << "Lowest Eigenvector : " << evalues << "Trace:  " << rhoTrace
                << std::endl;
    } else {
      throw std::runtime_error("Failed to evaluate Eigenvaleus\n");
    }
    return X;
    // return eigs.eigenvectors()
    //
  }
  auto vectorDot(const std::vector<double> &X) {
    // timer t1("vectorDot Sparse Solver");
    SparseA.setFromTriplets(coefficients.begin(), coefficients.end());
    std::vector<double> result(column, 0);
    for (int k = 0; k < SparseA.outerSize(); ++k) {
      for (Eigen::SparseMatrix<datatype>::InnerIterator it(SparseA, k); it;
           ++it) {
        // std::cout << "(" << it.row() << ","; // row index
        // std::cout << it.col() << ")\t"; // col index (here it is equal to k)
        result[it.row()] += it.value() * X[it.col()];
      }
    }
    return result;
  }
};