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>
// Spectra - header-only sparse eigenvalue solver
#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() {
    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 absolute value
#pragma omp parallel for reduction(+ : trace)
    for (size_t i = 0; i < column; i++) {
      X[i] = rightVec(i, idx).real();
      trace += X[i];
    }
    std::cout << "EigenValue" << eig[idx] << " trace :" << trace << std::endl;
    std::transform(X.begin(), X.end(), X.begin(), [trace](double x) { return x / trace; });
    return X;
  }

  auto vectorDot(std::vector<double> &a) {
    auto tmMat = qmat.dot(qmatrix<double>(a, column, 1));
    return std::vector<double>(tmMat.begin(), tmMat.end());
  }
};

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

public:
  explicit sparseEigen(size_t n = 0)
      : column(n), SparseA(Eigen::SparseMatrix<datatype>(n, n)) {}

  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() {
    SparseA.setFromTriplets(coefficients.begin(), coefficients.end());

    Spectra::SparseGenRealShiftSolve<double> op(SparseA);
    Spectra::GenEigsRealShiftSolver          eigs(op, 1, column / 2, 1e-6);

    eigs.init();
    eigs.compute(Spectra::SortRule::LargestMagn);

    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();

      for (size_t i = 0; i < column; i++) {
        X[i]     = eigVec(i, 0).real();
        rhoTrace = rhoTrace + X[i];
      }

      for (auto &aa : X) {
        aa = aa / rhoTrace;
      }
      std::cout << "Lowest Eigenvector : " << evalues << "Trace:  " << rhoTrace << std::endl;
    } else {
      throw std::runtime_error("Failed to evaluate Eigenvalues\n");
    }
    return X;
  }

  auto vectorDot(const std::vector<double> &X) {
    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) {
        result[it.row()] += it.value() * X[it.col()];
      }
    }
    return result;
  }
};