File: DavidsonSymEigs.cpp

package info (click to toggle)
spectra 1.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,788 kB
  • sloc: cpp: 23,044; ansic: 175; fortran: 131; makefile: 90
file content (123 lines) | stat: -rw-r--r-- 3,252 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <Eigen/Core>
#include <Eigen/SparseCore>
#include <Spectra/DavidsonSymEigsSolver.h>
#include <Spectra/MatOp/DenseSymMatProd.h>
#include <Spectra/MatOp/SparseSymMatProd.h>

#include "catch.hpp"

using namespace Spectra;

template <typename T>
using Matrix = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;

template <typename T>
using Vector = Eigen::Matrix<T, Eigen::Dynamic, 1>;

template <typename T>
using SpMatrix = Eigen::SparseMatrix<T>;

// Traits to obtain operation type from matrix type
template <typename MatType>
struct OpTypeTrait
{
    using Scalar = typename MatType::Scalar;
    using OpType = DenseSymMatProd<Scalar>;
};
template <typename T>
struct OpTypeTrait<SpMatrix<T>>
{
    using OpType = SparseSymMatProd<T>;
};

// Generate data for testing
template <typename Matrix>
Matrix gen_sym_data_dense(int n)
{
    Matrix mat = 0.03 * Matrix::Random(n, n);
    Matrix mat1 = mat + mat.transpose();
    for (Eigen::Index i = 0; i < n; i++)
    {
        mat1(i, i) += i + 1;
    }
    return mat1;
}

template <typename SpMatrix>
SpMatrix gen_sym_data_sparse(int n)
{
    // Eigen solver only uses the lower triangle of mat,
    // so we don't need to make mat symmetric here.
    double prob = 0.5;
    SpMatrix mat(n, n);
    std::default_random_engine gen;
    gen.seed(0);
    std::uniform_real_distribution<double> distr(0.0, 1.0);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (distr(gen) < prob)
                mat.insert(i, j) = 0.1 * (distr(gen) - 0.5);
            if (i == j)
            {
                mat.coeffRef(i, j) = i + 1;
            }
        }
    }
    return mat;
}

template <typename MatType>
void run_test(const MatType& mat, int nev, SortRule selection)
{
    using OpType = typename OpTypeTrait<MatType>::OpType;
    OpType op(mat);
    DavidsonSymEigsSolver<OpType> eigs(op, nev);
    int nconv = eigs.compute(selection);

    int niter = eigs.num_iterations();
    REQUIRE(nconv == nev);
    INFO("nconv = " << nconv);
    INFO("niter = " << niter);
    REQUIRE(eigs.info() == CompInfo::Successful);
    using T = typename OpType::Scalar;
    Vector<T> evals = eigs.eigenvalues();
    Matrix<T> evecs = eigs.eigenvectors();

    Matrix<T> resid = op * evecs - evecs * evals.asDiagonal();
    const T err = resid.array().abs().maxCoeff();

    INFO("||AU - UD||_inf = " << err);
    REQUIRE(err < 100 * Eigen::NumTraits<T>::dummy_precision());
}

template <typename MatType>
void run_test_set(const MatType& mat, int k)
{
    SECTION("Largest Value")
    {
        run_test<MatType>(mat, k, SortRule::LargestAlge);
    }

    SECTION("Smallest Value")
    {
        run_test<MatType>(mat, k, SortRule::SmallestAlge);
    }
}

TEMPLATE_TEST_CASE("Davidson Solver of dense symmetric real matrix [1000x1000]", "", double)
{
    std::srand(123);
    const Matrix<TestType> A = gen_sym_data_dense<Matrix<TestType>>(1000);
    int k = 10;
    run_test_set<Matrix<TestType>>(A, k);
}

TEMPLATE_TEST_CASE("Davidson Solver of sparse symmetric real matrix [1000x1000]", "", double)
{
    std::srand(123);
    int k = 10;
    const SpMatrix<TestType> A = gen_sym_data_sparse<SpMatrix<TestType>>(1000);
    run_test_set<SpMatrix<TestType>>(A, k);
}