1 #include <Eigen/CholmodSupport> 2 #include <unsupported/Eigen/AutoDiff> 8 Eigen::CholmodSupernodalLLT<Eigen::SparseMatrix<double> > {
9 typedef Eigen::CholmodSupernodalLLT<Eigen::SparseMatrix<double> > Base;
12 cholmod_factor* get_factor() {
13 return m_cholmodFactor;
15 StorageIndex* get_super() {
16 return static_cast<StorageIndex*
>(get_factor()->super);
18 StorageIndex* get_pi() {
19 return static_cast<StorageIndex*
>(get_factor()->pi);
21 StorageIndex* get_s() {
22 return static_cast<StorageIndex*
>(get_factor()->s);
24 StorageIndex* get_Perm() {
25 return static_cast<StorageIndex*
>(get_factor()->Perm);
27 StorageIndex* get_px() {
28 return static_cast<StorageIndex*
>(get_factor()->px);
31 return get_factor()->n;
34 return get_factor()->nsuper;
37 return get_factor()->xsize;
40 return static_cast<double*
>(get_factor()->x);
44 struct SupernodalInverseSubset {
47 typedef Base::StorageIndex StorageIndex;
48 typedef SparseMatrix<T> SpMat;
49 typedef Matrix<T, Dynamic, Dynamic> Mat;
50 typedef Map<Array<StorageIndex, Dynamic, 1> > Rows_ref;
57 std::shared_ptr<Base> chm;
58 std::vector<StorageIndex> col2super;
59 std::vector<StorageIndex> col2offset;
60 std::vector<StorageIndex> idg;
61 std::vector<StorageIndex> iwrk;
64 void init_col2super() {
65 if (col2super.size() > 0)
return;
66 col2super.resize( chm->get_n() );
67 StorageIndex *super = chm->get_super();
68 Index nsuper = chm->get_nsuper();
69 for (Index k=0, l=0; k < nsuper; k++) {
70 StorageIndex ncols = super[k + 1] - super[k];
71 while (ncols--) col2super[l++] = k;
74 void init_col2offset() {
75 if (col2offset.size() > 0)
return;
76 col2offset.resize( chm->get_n(), 0 );
77 StorageIndex *pi = chm->get_pi();
78 for (
size_t i = 1; i < col2offset.size(); i++) {
79 StorageIndex k = col2super[i - 1];
80 StorageIndex nrows = pi[k + 1] - pi[k];
81 col2offset[i] = col2offset[i - 1] + nrows;
84 void chm_index_scatter(StorageIndex col, StorageIndex* wrk) {
87 StorageIndex k = col2super[col];
88 StorageIndex *pi = chm->get_pi();
89 StorageIndex *s = chm->get_s();
90 for (StorageIndex i = pi[k], j = col2offset[col] ; i < pi[k + 1] ; i++) {
94 std::vector<StorageIndex> index_gather(
const SpMat &mat) {
95 std::vector<StorageIndex> ans;
96 StorageIndex *Perm = chm->get_Perm();
97 std::vector<StorageIndex> iPerm(mat.rows());
98 for (
size_t i=0; i<iPerm.size(); i++)
100 std::vector<StorageIndex> wrk(mat.rows());
101 for (StorageIndex k=0; k<mat.outerSize(); ++k) {
102 chm_index_scatter(iPerm[k], wrk.data());
103 for (
typename SpMat::InnerIterator it(mat, k); it; ++it) {
104 if (iPerm[it.row()] < iPerm[it.col()]) ans.push_back(-1);
105 else ans.push_back( wrk[iPerm[it.row()]] );
110 template<Operation Op>
111 void values(SpMat &mat) {
113 idg = index_gather(mat);
114 T* vptr = mat.valuePtr();
115 for (
size_t i=0; i<idg.size(); i++) {
118 ans[idg[i]] = vptr[i];
120 vptr[i] = ans[idg[i]];
124 Rows_ref rws(StorageIndex k) {
125 StorageIndex *pi = chm->get_pi();
126 StorageIndex *s = chm->get_s();
127 StorageIndex nrows = pi[k + 1] - pi[k];
128 return Rows_ref(s + pi[k], nrows);
130 StorageIndex nrow(StorageIndex k) {
131 StorageIndex *pi = chm->get_pi();
132 StorageIndex nrows = pi[k + 1] - pi[k];
135 StorageIndex ncol(StorageIndex k) {
136 StorageIndex *super = chm->get_super();
137 StorageIndex ncols = super[k + 1] - super[k];
140 template<Operation Op>
141 void denseBlock(Mat &ans,
148 if (iwrk.size() != chm->get_n())
149 iwrk.resize(chm->get_n());
151 std::vector<StorageIndex> rel_rows;
152 StorageIndex i_start = 0;
153 for (StorageIndex j = 0; j < nc; j++) {
154 StorageIndex k = col2super[c[j]];
155 auto X = getSuperNode(x, k);
156 StorageIndex *super = chm->get_super();
157 StorageIndex rel_col = c[j] - super[k];
158 if (j == 0 || k != col2super[c[j-1]]) {
161 Rows_ref rows = rws(k);
162 for (StorageIndex i=0; i<rows.size(); i++)
166 for (StorageIndex i=0; i<nr; i++)
167 rel_rows[i] = iwrk[r[i]];
170 while (i_start < nr && r[i_start] < c[j]) i_start++;
172 for (StorageIndex i = i_start; i < nr; i++) {
174 ans(i, j) = X(rel_rows[i], rel_col);
176 X(rel_rows[i], rel_col) = ans(i, j);
178 X(rel_rows[i], rel_col) += ans(i, j);
182 Map<Mat> getSuperNode(T* x,
184 StorageIndex *px = chm->get_px();
186 Map<Mat> ans(data, nrow(k), ncol(k));
190 void chol_get_cached_values() {
191 double* x = chm->get_x();
192 size_t n = chm->get_xsize();
194 for (
size_t i=0; i<n; i++) ans[i] = x[i];
199 ans.resize(0); ans.resize(chm->get_xsize(), 0);
203 StorageIndex *super = chm->get_super();
204 Index nsuper = chm->get_nsuper();
205 for (Index k=0; k < nsuper; k++) {
206 Rows_ref rows = rws(k);
208 StorageIndex ns = super[k + 1] - super[k];
209 StorageIndex np = rows.size() - ns;
210 StorageIndex* p = rows.data() + ns;
212 auto Xrs = getSuperNode(ans.data(), k);
213 Xrs.block(0, 0, ns, ns) =
214 Xrs.block(0, 0, ns, ns).llt().matrixL();
218 auto L = Xrs.block(0, 0, ns, ns);
219 auto Xps = Xrs.block(ns, 0, np, ns);
220 Xrs.block(ns, 0, np, ns) =
221 L.template triangularView<Lower>().
222 solve( Xps.transpose() ).
224 Xpp.template selfadjointView<Lower>().
225 rankUpdate(Xrs.block(ns, 0, np, ns), -1.);
226 denseBlock<Update>(Xpp, ans.data(), p, p, np, np);
233 StorageIndex *super = chm->get_super();
234 Index nsuper = chm->get_nsuper();
235 for (Index k=nsuper; k > 0; ) {
237 Rows_ref rows = rws(k);
239 StorageIndex ns = super[k + 1] - super[k];
240 StorageIndex np = rows.size() - ns;
241 StorageIndex* p = rows.data() + ns;
243 auto Xrs = getSuperNode(ans.data(), k);
244 auto Lss = Xrs.block(0, 0, ns, ns);
247 Lss_inv.setIdentity();
248 Lss.template triangularView<Lower>().
249 solveInPlace(Lss_inv);
250 Xrs.block(0, 0, ns, ns).setZero();
251 Xrs.block(0, 0, ns, ns).
252 template selfadjointView<Lower>().
253 rankUpdate(Lss_inv.transpose(), 1.);
256 denseBlock<Get>(Xpp, ans.data(), p, p, np, np);
257 Mat Lps = Xrs.block(ns, 0, np, ns);
259 Lss_inv.template triangularView<Lower>().
260 transpose() * Lps.transpose();
261 Xrs.block(ns, 0, np, ns) =
262 (-tmp * Xpp.template selfadjointView<Lower>()).transpose();
263 Xrs.block(0, 0, ns, ns) -= tmp * Xrs.block(ns, 0, np, ns);
267 SpMat operator()(SpMat x) {
269 if (isDouble<T>::value) {
270 chol_get_cached_values();
281 SupernodalInverseSubset(std::shared_ptr<Base> chm) :
283 void print_common() {
284 cholmod_print_common(
"C", &(chm->cholmod()));
Supernodal Cholesky factor with access to protected members.