47 using Scalar =
typename OpType::Scalar;
51 using RealScalar =
typename Eigen::NumTraits<Scalar>::Real;
52 using Index = Eigen::Index;
53 using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
54 using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
55 using RealMatrix = Eigen::Matrix<RealScalar, Eigen::Dynamic, Eigen::Dynamic>;
56 using RealVector = Eigen::Matrix<RealScalar, Eigen::Dynamic, 1>;
57 using RealArray = Eigen::Array<RealScalar, Eigen::Dynamic, 1>;
58 using BoolArray = Eigen::Array<bool, Eigen::Dynamic, 1>;
59 using MapMat = Eigen::Map<Matrix>;
60 using MapVec = Eigen::Map<Vector>;
61 using MapConstVec = Eigen::Map<const Vector>;
63 using ArnoldiOpType = ArnoldiOp<Scalar, OpType, BOpType>;
64 using LanczosFac = Lanczos<Scalar, ArnoldiOpType>;
75 std::vector<OpType> m_op_container;
84 RealVector m_ritz_val;
87 RealMatrix m_ritz_vec;
88 RealVector m_ritz_est;
89 BoolArray m_ritz_conv;
94 static std::vector<OpType> create_op_container(OpType&& rval)
96 std::vector<OpType> container;
97 container.emplace_back(std::move(rval));
102 void restart(Index k,
SortRule selection)
110 TridiagQR<RealScalar> decomp(m_ncv);
112 RealMatrix Q = RealMatrix::Identity(m_ncv, m_ncv);
115 const int nshift = m_ncv - k;
116 RealVector shifts = m_ritz_val.tail(nshift);
117 std::sort(shifts.data(), shifts.data() + nshift,
118 [](
const RealScalar& v1,
const RealScalar& v2) { return abs(v1) > abs(v2); });
120 for (Index i = 0; i < nshift; i++)
124 decomp.compute(m_fac.matrix_H().real(), shifts[i]);
131 m_fac.compress_H(decomp);
146 m_fac.factorize_from(k, m_ncv, m_nmatop);
148 retrieve_ritzpair(selection);
152 Index num_converged(
const RealScalar& tol)
157 const RealScalar eps = TypeTraits<RealScalar>::epsilon();
160 const RealScalar eps23 = pow(eps, RealScalar(2) / 3);
163 RealArray thresh = tol * m_ritz_val.head(m_nev).array().abs().max(eps23);
164 RealArray resid = m_ritz_est.head(m_nev).array().abs() * m_fac.f_norm();
166 m_ritz_conv = (resid < thresh);
168 return m_ritz_conv.count();
172 Index nev_adjusted(Index nconv)
178 const RealScalar near_0 = TypeTraits<RealScalar>::min() * RealScalar(10);
180 Index nev_new = m_nev;
181 for (Index i = m_nev; i < m_ncv; i++)
182 if (abs(m_ritz_est[i]) < near_0)
186 nev_new += (std::min)(nconv, (m_ncv - nev_new) / 2);
187 if (nev_new == 1 && m_ncv >= 6)
189 else if (nev_new == 1 && m_ncv > 2)
192 if (nev_new > m_ncv - 1)
199 void retrieve_ritzpair(
SortRule selection)
201 TridiagEigen<RealScalar> decomp(m_fac.matrix_H().real());
202 const RealVector& evals = decomp.eigenvalues();
203 const RealMatrix& evecs = decomp.eigenvectors();
206 std::vector<Index> ind = argsort(selection, evals, m_ncv);
209 for (Index i = 0; i < m_ncv; i++)
211 m_ritz_val[i] = evals[ind[i]];
212 m_ritz_est[i] = evecs(m_ncv - 1, ind[i]);
214 for (Index i = 0; i < m_nev; i++)
216 m_ritz_vec.col(i).noalias() = evecs.col(ind[i]);
223 virtual void sort_ritzpair(
SortRule sort_rule)
227 throw std::invalid_argument(
"unsupported sorting rule");
229 std::vector<Index> ind = argsort(sort_rule, m_ritz_val, m_nev);
231 RealVector new_ritz_val(m_ncv);
232 RealMatrix new_ritz_vec(m_ncv, m_nev);
233 BoolArray new_ritz_conv(m_nev);
235 for (Index i = 0; i < m_nev; i++)
237 new_ritz_val[i] = m_ritz_val[ind[i]];
238 new_ritz_vec.col(i).noalias() = m_ritz_vec.col(ind[i]);
239 new_ritz_conv[i] = m_ritz_conv[ind[i]];
242 m_ritz_val.swap(new_ritz_val);
243 m_ritz_vec.swap(new_ritz_vec);
244 m_ritz_conv.swap(new_ritz_conv);
251 HermEigsBase(OpType& op,
const BOpType& Bop, Index nev, Index ncv) :
255 m_ncv(ncv > m_n ? m_n : ncv),
258 m_fac(ArnoldiOpType(op, Bop), m_ncv),
261 if (nev < 1 || nev > m_n - 1)
262 throw std::invalid_argument(
"nev must satisfy 1 <= nev <= n - 1, n is the size of matrix");
264 if (ncv <= nev || ncv > m_n)
265 throw std::invalid_argument(
"ncv must satisfy nev < ncv <= n, n is the size of matrix");
269 HermEigsBase(OpType&& op,
const BOpType& Bop, Index nev, Index ncv) :
270 m_op_container(create_op_container(std::move(op))),
271 m_op(m_op_container.front()),
274 m_ncv(ncv > m_n ? m_n : ncv),
277 m_fac(ArnoldiOpType(m_op, Bop), m_ncv),
280 if (nev < 1 || nev > m_n - 1)
281 throw std::invalid_argument(
"nev must satisfy 1 <= nev <= n - 1, n is the size of matrix");
283 if (ncv <= nev || ncv > m_n)
284 throw std::invalid_argument(
"ncv must satisfy nev < ncv <= n, n is the size of matrix");
303 void init(
const Scalar* init_resid)
306 m_ritz_val.resize(m_ncv);
307 m_ritz_vec.resize(m_ncv, m_nev);
308 m_ritz_est.resize(m_ncv);
309 m_ritz_conv.resize(m_nev);
311 m_ritz_val.setZero();
312 m_ritz_vec.setZero();
313 m_ritz_est.setZero();
314 m_ritz_conv.setZero();
320 MapConstVec v0(init_resid, m_n);
321 m_fac.init(v0, m_nmatop);
333 SimpleRandom<Scalar> rng(0);
334 Vector init_resid = rng.random_vec(m_n);
335 init(init_resid.data());
364 m_fac.factorize_from(1, m_ncv, m_nmatop);
365 retrieve_ritzpair(selection);
367 Index i, nconv = 0, nev_adj;
368 for (i = 0; i < maxit; i++)
370 nconv = num_converged(tol);
374 nev_adj = nev_adjusted(nconv);
375 restart(nev_adj, selection);
378 sort_ritzpair(sorting);
383 return (std::min)(m_nev, nconv);
413 const Index nconv = m_ritz_conv.count();
414 RealVector res(nconv);
420 for (Index i = 0; i < m_nev; i++)
424 res[j] = m_ritz_val[i];
443 const Index nconv = m_ritz_conv.count();
444 nvec = (std::min)(nvec, nconv);
445 Matrix res(m_n, nvec);
450 RealMatrix ritz_vec_conv(m_ncv, nvec);
452 for (Index i = 0; i < m_nev && j < nvec; i++)
456 ritz_vec_conv.col(j).noalias() = m_ritz_vec.col(i);
461 res.noalias() = m_fac.matrix_V() * ritz_vec_conv;