LIBINT 2.9.0
pivoted_cholesky.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_lib_libint_pivoted_cholesky_h_
22#define _libint2_src_lib_libint_pivoted_cholesky_h_
23
24#include <Eigen/Dense>
25#include <algorithm>
26#include <iostream>
27
28namespace libint2 {
29
36inline std::vector<size_t> pivoted_cholesky(const Eigen::MatrixXd &A,
37 const double tolerance,
38 const std::vector<size_t> &pivot) {
39 // number of elements in A
40 const auto n = A.rows();
41 // diagonal elements of A
42 std::vector<double> d(n);
43 // initial error
44 auto error = A.diagonal()[0];
45 for (size_t i = 0; i < n; ++i) {
46 d[i] = A.diagonal()[i];
47 error = std::max(d[i], error);
48 }
49
50 // Return matrix
51 Eigen::MatrixXd L(n, n);
52
53 // loop index
54 size_t m = 0;
55
56 // copy input pivot indices
57 std::vector<size_t> piv;
58 piv.reserve(n);
59 for (size_t i = 0; i < n; ++i) {
60 piv.push_back(pivot[i]);
61 }
62
63 while (error > tolerance && m < n) {
64 // update pivot indices
65 // Errors in pivoted order
66 std::vector<double> err(d.size());
67 for (size_t i = 0; i < d.size(); ++i) {
68 err[i] = d[piv[i]];
69 }
70 // error vector after mth element
71 std::vector<double> err2(err.begin() + m, err.end());
72 std::vector<size_t> idx(err2.size());
73 for (size_t i = 0; i < idx.size(); ++i) {
74 idx[i] = i;
75 }
76 // sort indices
77 std::sort(idx.begin(), idx.end(),
78 [&err2](size_t i1, size_t i2) { return err2[i1] > err2[i2]; });
79 // subvector of piv
80 std::vector<size_t> piv_subvec(piv.size() - m);
81 for (size_t i = 0; i < piv_subvec.size(); ++i) {
82 piv_subvec[i] = piv[i + m];
83 }
84 // sort piv
85 for (size_t i = 0; i < idx.size(); ++i) {
86 piv[i + m] = piv_subvec[idx[i]];
87 }
88
89 // TODO: find a better way to update pivot indices
90
91 // current pivot index
92 size_t pim = piv[m];
93 // compute diagonal element
94 L(m, pim) = std::sqrt(d[pim]);
95
96 // off-diagonal elements
97 for (size_t i = m + 1; i < n; ++i) {
98 auto pii = piv[i];
99 // compute element
100 L(m, pii) =
101 (m > 0) ? (A(pim, pii) - L.col(pim).head(m).dot(L.col(pii).head(m))) /
102 L(m, pim)
103 : (A(pim, pii)) / L(m, pim);
104 // update d
105 d[pii] -= L(m, pii) * L(m, pii);
106 }
107 // update error
108 if (m + 1 < n) {
109 error = d[piv[m + 1]];
110 for (size_t i = m + 1; i < n; ++i) {
111 error = std::max(d[piv[i]], error);
112 }
113 }
114 // increase m
115 m++;
116 }
117 // Transpose to get Cholesky vectors as columns
118 L.transposeInPlace();
119 // Drop unnecessary columns
120 L.conservativeResize(n, m);
121
122 // return reduced pivot indices
123 std::vector<size_t> reduced_piv;
124 reduced_piv.reserve(m);
125 for (size_t i = 0; i < m; ++i) {
126 reduced_piv.push_back(piv[i]);
127 }
128
129 return reduced_piv;
130}
131
132} // namespace libint2
133
134#endif //_libint2_src_lib_libint_pivoted_cholesky_h_
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24
std::vector< size_t > pivoted_cholesky(const Eigen::MatrixXd &A, const double tolerance, const std::vector< size_t > &pivot)
computes the pivoted Cholesky decomposition of a symmetric positive definite matrix
Definition pivoted_cholesky.h:36