b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2matrix_sym_compressed.H
1//------------------------------------------------------------------------
2// b2matrix_sym_compressed.H --
3//
4// A framework for generic linear algebraic (matrix) computations.
5//
6// written by Mathias Doreille
7//
8// Copyright (c) 2004-2012,2016
9// SMR Engineering & Development SA
10// 2502 Bienne, Switzerland
11//
12// All Rights Reserved. Proprietary source code. The contents of
13// this file may not be disclosed to third parties, copied or
14// duplicated in any form, in whole or in part, without the prior
15// written permission of SMR.
16//------------------------------------------------------------------------
17
18#ifndef B2MATRIX_SYM_COMPRESSED_H_
19#define B2MATRIX_SYM_COMPRESSED_H_
20
21#include <ostream>
22#include <unordered_map>
23
24#include "b2linear_algebra_def.H"
25#include "b2sparse_solver.H"
26#include "b2vector_index.H"
27
28namespace b2000::b2linalg {
29
30struct Msym_compressed_col {
31 typedef Msym_compressed_col_ref base;
32 typedef Msym_compressed_col_st_constref const_base;
33 typedef Msym_compressed_col copy;
34 typedef Msym_compressed_col_update_inv inverse;
35};
36
37template <typename T>
38class Matrix<T, Msym_compressed_col> {
39public:
40 Matrix(size_t s1_ = 0, size_t s2_ = 0, size_t snn_ = 0)
41 : s1(s1_), si(s2_ + 1), m(snn_), index(snn_) {}
42
43 Matrix(const Matrix& m_) : s1(m_.s1), si(m_.si), m(m_.m), index(m_.index) {}
44
45 template <typename T1>
46 Matrix& operator=(const Matrix<T1, Msym_compressed_col>& m_) {
47 s1 = m_.s1;
48 si = m_.si;
49 m.assign(m_.m.begin(), m_.m.end());
50 index = m_.index;
51 return *this;
52 }
53
54 template <typename T1>
55 Matrix(const Matrix<T1, Msym_compressed_col>& m_)
56 : s1(m_.s1),
57 si(m_.si.begin(), m_.si.end()),
58 m(m_.m.begin(), m_.m.end()),
59 index(m_.index.begin(), m_.index.end()) {}
60
61 bool is_null() const { return this == &null; }
62
63 void set_zero() {
64 std::fill(si.begin(), si.end(), 0);
65 index.clear();
66 m.clear();
67 }
68
69 void resize(size_t s1_, size_t s2_) {
70 s1 = s1_;
71 if (size2() < s2_) {
72 si.insert(si.end(), s2_ - size2(), si.back());
73 } else {
74 si.resize(s2_ + 1);
75 }
76 }
77
78 void resize(size_t s1_, size_t s2_, size_t snn = 0) {
79 s1 = s1_;
80 si.resize(s2_ + 1);
81 index.resize(snn);
82 m.resize(snn);
83 }
84
85 void swap(std::vector<size_t>& colind, std::vector<size_t>& rowind, std::vector<T>& value) {
86 s1 = colind.size() - 1;
87 si.swap(colind);
88 index.swap(rowind);
89 m.swap(value);
90 }
91
92 void get_values(size_t*& colind, size_t*& rowind, T*& value) {
93 colind = &si[0];
94 rowind = &index[0];
95 value = &m[0];
96 }
97
98 std::pair<size_t, size_t> size() const {
99 return std::pair<size_t, size_t>(s1, si.size() == 0 ? 0 : si.size() - 1);
100 }
101
102 size_t size1() const { return s1; }
103
104 size_t size2() const { return si.size() == 0 ? 0 : si.size() - 1; }
105
106 size_t nb_nonzero() const { return si.back(); }
107
108 T operator()(size_t i, size_t j) const {
109 if (i < j) { std::swap(i, j); }
110 std::vector<size_t>::const_iterator s = index.begin() + si[j];
111 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
112 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
113 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
114 return 0;
115 }
116
117 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
118 l << "symmetric column compressed matrix of size (" << m.s1 << ", " << m.s1 << ") ";
119 l.write(m.si.size(), &m.si[0], 1, "colind");
120 l.write(m.index.size(), &m.index[0], 1, "rowind");
121 l.write(m.m.size(), &m.m[0], 1, "value");
122 return l;
123 }
124
125 static Matrix null;
126
127private:
128 size_t s1;
129 std::vector<size_t> si;
130 std::vector<T> m;
131 std::vector<size_t> index;
132 MVFRIEND;
133};
134
135template <typename T>
136Matrix<T, Msym_compressed_col> Matrix<T, Msym_compressed_col>::null;
137
138struct Msym_compressed_col_ref {
139 typedef Msym_compressed_col_ref base;
140 typedef Msym_compressed_col_st_constref const_base;
141 typedef Msym_compressed_col copy;
142 typedef Msym_compressed_col_update_inv inverse;
143};
144
145template <typename T>
146class Matrix<T, Msym_compressed_col_ref> {
147public:
148 Matrix() : s1(0), s2(0), si(0), index(0), m(0) {}
149
150 Matrix(size_t s1_, size_t s2_, size_t snn_, size_t* si_, size_t* index_, T* m_)
151 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_) {}
152
153 Matrix(const Matrix& m_) : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
154
155 Matrix(Matrix<T, Msym_compressed_col>& m_)
156 : s1(m_.s1), s2(m_.si.size() - 1), si(&m_.si[0]), index(&m_.index[0]), m(&m_.m[0]) {}
157
158 bool is_null() const { return m == 0; }
159
160 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(s1, s2); }
161
162 size_t size1() const { return s1; }
163
164 size_t size2() const { return s2; }
165
166 T operator()(size_t i, size_t j) const {
167 if (i < j) { std::swap(i, j); }
168 const size_t* s = index + si[j];
169 const size_t* e = index + si[j + 1];
170 const size_t* ii = std::lower_bound(s, e, i);
171 if (ii < e && *ii == i) { return m[ii - index]; }
172 return 0;
173 }
174
175 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
176 l << "symmetric column compressed matrix of size (" << m.s1 << ", " << m.s1 << ") ";
177 l.write(m.s2 + 1, m.si, 1, "colind");
178 l.write(m.si[m.s2], m.index, 1, "rowind");
179 l.write(m.si[m.s2], m.m, 1, "value");
180 return l;
181 }
182
183 static Matrix null;
184
185private:
186 size_t s1;
187 size_t s2;
188 size_t* si;
189 size_t* index;
190 T* m;
191 MVFRIEND;
192};
193
194template <typename T>
195Matrix<T, Msym_compressed_col_ref> Matrix<T, Msym_compressed_col_ref>::null;
196
197struct Msym_compressed_col_constref {
198 typedef Msym_compressed_col_st_constref base;
199 typedef Msym_compressed_col_st_constref const_base;
200 typedef Msym_compressed_col copy;
201 typedef Msym_compressed_col_update_inv inverse;
202};
203
204template <typename T>
205class Matrix<T, Msym_compressed_col_constref> {
206public:
207 Matrix() : s1(0), s2(0), si(0), index(0), m(0) {}
208
209 Matrix(
210 size_t s1_, size_t s2_, size_t snn_, const size_t* si_, const size_t* index_, const T* m_)
211 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_) {}
212
213 Matrix(const Matrix& m_) : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
214
215 Matrix(const Matrix<T, Msym_compressed_col_ref>& m_)
216 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
217
218 Matrix(const Matrix<T, Msym_compressed_col>& m_)
219 : s1(m_.s1), s2(m_.si.size() - 1), si(&m_.si[0]), index(&m_.index[0]), m(&m_.m[0]) {}
220
221 bool is_null() const { return m == 0; }
222
223 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(s1, s2); }
224
225 size_t size1() const { return s1; }
226
227 size_t size2() const { return s2; }
228
229 T operator()(size_t i, size_t j) const {
230 if (i < j) { std::swap(i, j); }
231 const size_t* s = index + si[j];
232 const size_t* e = index + si[j + 1];
233 const size_t* ii = std::lower_bound(s, e, i);
234 if (ii < e && *ii == i) { return m[ii - index]; }
235 return 0;
236 }
237
238 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
239 l << "symmetric column compressed matrix of size (" << m.s1 << ", " << m.s1 << ") ";
240 l.write(m.s2 + 1, m.si, 1, "colind");
241 l.write(m.si[m.s2], m.index, 1, "rowind");
242 l.write(m.si[m.s2], m.m, 1, "value");
243 return l;
244 }
245
246 static Matrix null;
247
248private:
249 size_t s1;
250 size_t s2;
251 const size_t* si;
252 const size_t* index;
253 const T* m;
254 MVFRIEND;
255};
256
257template <typename T>
258Matrix<T, Msym_compressed_col_constref> Matrix<T, Msym_compressed_col_constref>::null;
259
260struct Msym_compressed_col_st_constref {
261 typedef Msym_compressed_col_st_constref base;
262 typedef Msym_compressed_col_st_constref const_base;
263 typedef Msym_compressed_col copy;
264 typedef Msym_compressed_col_update_inv inverse;
265};
266
267template <typename T>
268class Matrix<T, Msym_compressed_col_st_constref> {
269public:
270 Matrix() : s1(0), s2(0), si(0), index(0), m(0), scale(0) {}
271
272 Matrix(
273 size_t s1_, size_t s2_, size_t snn_, const size_t* si_, const size_t* index_, const T* m_,
274 T scale_)
275 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_), scale(scale_) {}
276
277 Matrix(const Matrix& m_)
278 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m), scale(m_.scale) {}
279
280 Matrix(const Matrix<T, Msym_compressed_col_ref>& m_)
281 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m), scale(1) {}
282
283 Matrix(const Matrix<T, Msym_compressed_col_constref>& m_)
284 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m), scale(1) {}
285
286 Matrix(const Matrix<T, Msym_compressed_col>& m_)
287 : s1(m_.s1),
288 s2(m_.si.size() - 1),
289 si(&m_.si[0]),
290 index(&m_.index[0]),
291 m(&m_.m[0]),
292 scale(1) {}
293
294 Matrix(Matrix<T, Msym_compressed_col_update_inv>& m_) : scale(1) {
295 m_.value_to_ccarray();
296 s1 = m_.si.size() - 1;
297 s2 = s1;
298 si = &m_.si[0];
299 index = &m_.index[0];
300 m = &m_.m[0];
301 }
302
303 bool is_null() const { return m == 0; }
304
305 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(s1, s2); }
306
307 size_t size1() const { return s1; }
308
309 size_t size2() const { return s2; }
310
311 T operator()(size_t i, size_t j) const {
312 if (i < j) { std::swap(i, j); }
313 const size_t* s = index + si[j];
314 const size_t* e = index + si[j + 1];
315 const size_t* ii = std::lower_bound(s, e, i);
316 if (ii < e && *ii == i) { return scale * m[ii - index]; }
317 return 0;
318 }
319
320 Matrix& operator*(T scale_) {
321 scale *= scale_;
322 return *this;
323 }
324
325 static Matrix null;
326
327private:
328 size_t s1;
329 size_t s2;
330 const size_t* si;
331 const size_t* index;
332 const T* m;
333 T scale;
334 MVFRIEND;
335};
336
337template <typename T>
338Matrix<T, Msym_compressed_col_st_constref> Matrix<T, Msym_compressed_col_st_constref>::null;
339
340struct Msym_compressed_col_update_inv {
341 typedef Msym_compressed_col_ref base;
342 typedef Msym_compressed_col_st_constref const_base;
343 typedef Msym_compressed_col_update_inv copy;
344 typedef Msym_compressed_col_update_inv inverse;
345};
346
347template <typename T>
348class Matrix<T, Msym_compressed_col_update_inv> {
349public:
350 Matrix(
351 size_t s1_ = 0,
352 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
353 const Dictionary& dictionary_ = Dictionary::get_empty())
354 : value(s1_), solver(0), connectivity(connectivity_), dictionary(&dictionary_) {}
355
356 Matrix(const Matrix& m_)
357 : si(m_.si),
358 m(m_.m),
359 index(m_.index),
360 value(m_.value),
361 solver(0),
362 connectivity(m_.connectivity),
363 dictionary(m_.dictionary) {}
364
365 virtual ~Matrix() { delete solver; }
366
367 void resize(
368 size_t s, SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
369 const Dictionary& dictionary_ = Dictionary::get_empty()) {
370 if (si.empty()) {
371 value.resize(s);
372 } else {
374 }
375 if (connectivity_ != sparse_matrix_connectivity_unknown) { connectivity = connectivity_; }
376 if (&dictionary_ != &Dictionary::get_empty()) { dictionary = &dictionary_; }
377 }
378
379 void resize(
380 size_t s1, size_t s2,
381 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
382 const Dictionary& dictionary_ = Dictionary::get_empty()) {
383 if (s1 != s2) { Exception() << THROW; }
384 resize(s1);
385 if (connectivity_ != sparse_matrix_connectivity_unknown) { connectivity = connectivity_; }
386 if (&dictionary_ != &Dictionary::get_empty()) { dictionary = &dictionary_; }
387 }
388
389 void set_same_structure(const Matrix& m_) {
390 const_cast<Matrix&>(m_).value_to_ccarray();
391 si = m_.si;
392 index = m_.index;
393 m.resize(m_.m.size());
394 std::fill(m.begin(), m.end(), 0);
395 connectivity = m_.connectivity;
396 dictionary = m_.dictionary;
397 }
398
399 virtual void set_zero() {
400 value.clear();
401 si.clear();
402 index.clear();
403 m.clear();
404 delete solver;
405 solver = 0;
406 }
407
408 virtual bool is_null() const { return this == &null; }
409
410 virtual void set_zero_same_struct() {
411 for (typename std::vector<std::vector<std::pair<size_t, T>>>::iterator i = value.begin();
412 i != value.end(); ++i) {
413 i->clear();
414 }
415 std::fill(m.begin(), m.end(), 0);
416 if (solver) { solver->update_value(); }
417 }
418
419 std::pair<size_t, size_t> size() const {
420 size_t s;
421 if (si.empty()) {
422 s = value.size();
423 } else {
424 s = si.size() - 1;
425 }
426 return std::pair<size_t, size_t>(s, s);
427 }
428
429 size_t get_nb_nonzero() const {
430 if (si.empty()) {
431 size_t r = 0;
432 for (size_t i = 0; i != value.size(); ++i) { r += value[i].size(); }
433 }
434 return index.size();
435 }
436
437 size_t size1() const {
438 if (si.empty()) { return value.size(); }
439 return si.size() - 1;
440 }
441
442 size_t size2() const {
443 if (si.empty()) { return value.size(); }
444 return si.size() - 1;
445 }
446
453 void InitializeRow(size_t row, const std::map<size_t, T>& row_contributions) {
454 value[row].reserve(row_contributions.size());
455 auto pos{begin(row_contributions)};
456
457 for (; pos != end(row_contributions); pos++) {
458 value[row].push_back(std::make_pair(pos->first, pos->second));
459 }
460 }
461
467 T operator()(size_t i, size_t j) const {
468 if (i < j) { std::swap(i, j); }
469 if (si.empty()) {
470 typename std::vector<std::pair<size_t, T>>::const_iterator ii = std::lower_bound(
471 value[j].begin(), value[j].end(), std::pair<size_t, T>(i, 0),
472 CompareFirstOfPair());
473
474 if (ii != value[j].end() && ii->first == i) { return ii->second; }
475
476 } else {
477 std::vector<size_t>::const_iterator s = index.begin() + si[j];
478 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
479 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
480 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
481 }
482 return 0;
483 }
484
491 T& operator()(size_t i, size_t j) {
494 if (i < j) { std::swap(i, j); }
495
496 if (si.empty()) {
497 typename std::vector<std::pair<size_t, T>>::iterator ii = std::lower_bound(
498 value[j].begin(), value[j].end(), std::pair<size_t, T>(i, T{}),
499 CompareFirstOfPair());
500 if (ii != value[j].end() && ii->first == i) { return ii->second; }
501 } else {
502 std::vector<size_t>::const_iterator s = index.begin() + si[j];
503 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
504 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
505 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
506 }
507
508 static T zero = 0;
509 return zero;
510 }
511
512 Matrix& operator+=(const Matrix<T, Mstructured_constref<Mpacked_st_constref>>& m_) {
513 if (size() != m_.size()) {
514 Exception() << "The two matrix do not have the same size, " << size() << " and "
515 << m_.size() << THROW;
516 }
517 std::vector<std::pair<size_t, T>> tmp;
518 tmp.reserve(m_.m.s);
519 for (size_t j = 0; j != m_.m.s; ++j) {
520 tmp.clear();
521 size_t index_j = m_.index[j];
522 for (size_t i = 0; i != m_.m.s; ++i) {
523 size_t index_i = m_.index[i];
524 if (index_i >= index_j) {
525 tmp.push_back(std::pair<size_t, T>(index_i, m_.m(i, j)));
526 }
527 }
528 std::sort(tmp.begin(), tmp.end(), CompareFirstOfPair());
529 add_colomn(index_j, tmp.begin(), tmp.end());
530 }
531 return *this;
532 }
533
534 Matrix& operator+=(
535 const Matrix<
536 T,
537 MMProd<
538 MMProd<
539 Mcompressed_col_st_constref, Mstructured_constref<Mpacked_st_constref>>,
540 Mcompressed_col_st_constref>>& m_) {
541 if (size1() < m_.size1()) {
542 Exception() << "The two matrix do not have the same size, " << size() << " and "
543 << m_.size() << THROW;
544 }
545 if (m_.m1.m1.trans == true || m_.m2.trans == false || m_.m1.m1.si != m_.m2.si
546 || m_.m1.m1.index != m_.m2.index || m_.m1.m1.m != m_.m2.m) {
548 }
549
550 const size_t* colind = m_.m2.si;
551 const size_t* rowind = m_.m2.index;
552 const T* value_ = m_.m2.m;
553 const size_t input_size = m_.m1.m2.m.s;
554 const size_t* input_dof_numbering = m_.m1.m2.index;
555
556 bool new_output_matrix = false;
557 std::map<size_t, size_t> tmp_rowind;
558 const size_t* input_dof_numbering_begin = input_dof_numbering;
559 const size_t* const input_dof_numbering_end = input_dof_numbering_begin + input_size;
560 while (input_dof_numbering_begin != input_dof_numbering_end) {
561 const size_t* rowind_begin = rowind + colind[*input_dof_numbering_begin];
562 const size_t* const rowind_end = rowind + colind[*input_dof_numbering_begin + 1];
563 const T* value_begin = value_ + colind[*input_dof_numbering_begin];
564 std::pair<size_t, size_t> tmp_rowind_insert(
565 0, input_dof_numbering_begin - input_dof_numbering);
566 while (rowind_begin != rowind_end) {
567 tmp_rowind_insert.first = *rowind_begin;
568 if (!tmp_rowind.insert(tmp_rowind_insert).second || *value_begin != T(1)) {
569 new_output_matrix = true;
570 }
571 ++rowind_begin;
572 ++value_begin;
573 }
574 ++input_dof_numbering_begin;
575 }
576 const size_t output_size = tmp_rowind.size();
577 std::vector<std::pair<size_t, size_t>> output_dof_numbering(
578 tmp_rowind.begin(), tmp_rowind.end());
579 std::vector<std::pair<size_t, T>> output_col(output_size);
580 for (size_t i = 0; i != output_size; ++i) {
581 output_col[i].first = output_dof_numbering[i].first;
582 }
583 const Matrix<T, Mpacked_st_constref>& input_matrix = m_.m1.m2.m;
584 const T scale_ = m_.scale * m_.m1.scale * m_.m1.m1.scale * m_.m2.scale;
585 if (!new_output_matrix) {
586 for (size_t j = 0; j != output_size; ++j) {
587 size_t jj = output_dof_numbering[j].second;
588 for (size_t i = j; i != output_size; ++i) {
589 output_col[i].second =
590 scale_ * input_matrix(output_dof_numbering[i].second, jj);
591 }
592 add_colomn(output_dof_numbering[j].first, output_col.begin() + j, output_col.end());
593 }
594 } else {
595 {
596 std::map<size_t, size_t>::iterator ii = tmp_rowind.begin();
597 for (size_t i = 0; i != output_size; ++i, ++ii) { ii->second = i; }
598 }
599 T* output_value = TemporaryBuffer<T>::get(output_size * input_size);
600 T* output_value_l = output_value;
601 for (size_t j = 0; j != input_size; ++j, output_value_l += output_size) {
602 for (size_t i = 0; i != input_size; ++i) {
603 const size_t* rowind_begin = rowind + colind[input_dof_numbering[i]];
604 const size_t* const rowind_end = rowind + colind[input_dof_numbering[i] + 1];
605 const T* value_begin = value_ + colind[input_dof_numbering[i]];
606 const T v = scale_ * input_matrix(j, i);
607 while (rowind_begin != rowind_end) {
608 output_value_l[tmp_rowind[*rowind_begin++]] += *value_begin++ * v;
609 }
610 }
611 }
612 for (size_t i = 0; i != output_size; ++i) {
613 for (size_t j = 0; j != output_size; ++j) { output_col[j].second = 0; }
614 for (size_t j = 0; j != input_size; ++j) {
615 const size_t* rowind_begin = rowind + colind[input_dof_numbering[j]];
616 const size_t* const rowind_end = rowind + colind[input_dof_numbering[j] + 1];
617 const T* value_begin = value_ + colind[input_dof_numbering[j]];
618 const T v = output_value[i + j * output_size];
619 while (rowind_begin != rowind_end) {
620 output_col[tmp_rowind[*rowind_begin++]].second += *value_begin++ * v;
621 }
622 }
623 add_colomn(output_dof_numbering[i].first, output_col.begin() + i, output_col.end());
624 }
625 std::fill_n(output_value, output_size * input_size, 0);
626 }
627 return *this;
628 }
629
630 Matrix& operator+=(
631 const Matrix<
632 T, MMProd<
633 MMProd<Mcompressed_col_st_constref, Msym_compressed_col_st_constref>,
634 Mcompressed_col_st_constref>>& m_) {
635 if (size() < m_.size()) {
636 Exception() << "The two matrix do not have the same size, " << size() << " and "
637 << m_.size() << THROW;
638 }
639 if (m_.m1.m1.trans == true || m_.m2.trans == false || m_.m1.m1.si != m_.m2.si
640 || m_.m1.m1.index != m_.m2.index || m_.m1.m1.m != m_.m2.m) {
642 }
643
644 Matrix<T, Mcompressed_col> M2;
645 M2 = m_.m1.m2;
646 Matrix<T, Mcompressed_col> M12;
647 M12 = m_.m1.scale * (m_.m1.m1 * M2);
648 M2 = m_.m2;
649 Matrix<T, Mcompressed_col> M123;
650 M123 = m_.scale * (M12 * M2);
651
652 std::vector<std::pair<size_t, T>> res_tmp;
653 size_t mi = M123.si[0];
654 for (size_t j = 0; j != M123.s1; ++j) {
655 const size_t mi_end = M123.si[j + 1];
656 for (; mi != mi_end && M123.index[mi] < j; ++mi) { ; }
657 if (mi != mi_end) {
658 res_tmp.resize(mi_end - mi);
659 for (size_t i = 0; mi != mi_end; ++i, ++mi) {
660 res_tmp[i].first = M123.index[mi];
661 res_tmp[i].second = M123.m[mi];
662 }
663 add_colomn(j, res_tmp.begin(), res_tmp.end());
664 }
665 }
666 return *this;
667 }
668
669 Matrix& operator+=(
670 const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
671 if (size1() < m_.size1() || size2() < m_.size2()) {
672 Exception() << "The two matrix do not have the same size, " << size() << " and "
673 << m_.size() << THROW;
674 }
675
676 if (m_.trans || m_.m1.trans || !m_.m2.trans) { UnimplementedError() << THROW; }
677 if (m_.m1.m != m_.m2.m) { Exception() << THROW; }
678
679 Matrix<T, Mcompressed_col> m_m2;
680 m_m2 = m_.m2;
681
682 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
683 const size_t end_list_flag = m_.m1.size1();
684 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
685
686 T scale = m_.scale * m_.m1.scale;
687 const size_t* b_colind_begin = &m_m2.si[0];
688 const size_t* const b_colind_end = b_colind_begin + m_m2.size2();
689 size_t end_list = end_list_flag;
690 size_t col = 0;
691 while (b_colind_begin != b_colind_end) {
692 const size_t* b_rowind_begin = &m_m2.index[*b_colind_begin];
693 const T* b_value_begin = &m_m2.m[*b_colind_begin];
694 const size_t* const b_rowind_end = &m_m2.index[*++b_colind_begin];
695 while (b_rowind_begin != b_rowind_end) {
696 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
697 const size_t* const a_rowind_end = m_.m1.index + m_.m1.si[*b_rowind_begin++ + 1];
698 while (a_rowind_begin != a_rowind_end && *a_rowind_begin < col) {
699 ++a_rowind_begin;
700 }
701 const T* a_value_begin = m_.m1.m + (a_rowind_begin - m_.m1.index);
702 const T b_value_begin_v = *b_value_begin++;
703 while (a_rowind_begin != a_rowind_end) {
704 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
705 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
706 tmp_index[*a_rowind_begin] = end_list;
707 end_list = *a_rowind_begin;
708 }
709 ++a_rowind_begin;
710 }
711 }
712 std::vector<std::pair<size_t, T>> res_tmp;
713 while (end_list != end_list_flag) {
714 res_tmp.push_back(std::pair<size_t, T>(end_list, scale * tmp_value[end_list]));
715 const size_t end_list_next = tmp_index[end_list];
716 tmp_index[end_list] = std::numeric_limits<size_t>::max();
717 tmp_value[end_list] = T(0);
718 end_list = end_list_next;
719 }
720
721 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
722 add_colomn(col++, res_tmp.begin(), res_tmp.end());
723 }
724 return *this;
725 }
726
727 Matrix& operator+=(const Matrix& m_) {
728 value_to_ccarray();
729 const_cast<Matrix&>(m_).value_to_ccarray();
730 if (size1() != m_.size1()) {
731 Exception() << "The two matrices do not have the same size." << THROW;
732 }
733 if (!std::equal(si.begin(), si.end(), m_.si.begin())
734 || !std::equal(
735 index.begin() + si.front(), index.begin() + si.back(),
736 m_.index.begin() + m_.si.front())) {
738 }
739 blas::axpy(m.size(), 1, &m_.m[0], 1, &m[0], 1);
740 return *this;
741 }
742
743 Matrix& operator-=(const Matrix& m_) {
744 if (size1() != m_.size1()) {
745 Exception() << "The two matrices do not have the same size." << THROW;
746 }
747 value_to_ccarray();
748 const_cast<Matrix&>(m_).value_to_ccarray();
749 if (!std::equal(si.begin(), si.end(), m_.si.begin())
750 || !std::equal(
751 index.begin() + si.front(), index.begin() + si.back(),
752 m_.index.begin() + m_.si.front())) {
753 if (si.back() == 0) {
754 si = m_.si;
755 index = m_.index;
756 m = m_.m;
757 blas::scal(m.size(), -1, &m[0], 1);
758 } else {
760 }
761 } else {
762 blas::axpy(m.size(), -1, &m_.m[0], 1, &m[0], 1);
763 }
764 return *this;
765 }
766
767 Matrix& operator+=(const Matrix<T, Msym_compressed_col_st_constref>& m_) {
768 if (m_.size1() != m_.size2()) { UnimplementedError() << THROW; }
769 value_to_ccarray();
770 if (!std::equal(si.begin(), si.end(), m_.si)
771 || !std::equal(
772 index.begin() + si[0], index.begin() + si[size2()], m_.index + m_.si[0])) {
773 if (si.back() == 0) {
774 si.assign(m_.si, m_.si + m_.s2 + 1);
775 index.assign(m_.index, m_.index + si.back());
776 m.assign(m_.m, m_.m + si.back());
777 blas::scal(m.size(), m_.scale, &m[0], 1);
778 } else {
779 size_t s_i = m_.si[0];
780 size_t d_i = si[0];
781 for (size_t j = 1; j != m_.s2 + 1; ++j) {
782 const size_t s_i_end = m_.si[j];
783 const size_t d_i_end = si[j];
784 for (; d_i != d_i_end && s_i != s_i_end; ++d_i) {
785 if (m_.index[s_i] == index[d_i]) { m[d_i] += m_.scale * m_.m[s_i++]; }
786 }
787 d_i = d_i_end;
788 if (s_i != s_i_end) {
789 if (s_i_end - s_i == 1 && m_.m[s_i] == T(0)) {
790 ++s_i;
791 } else {
792 Exception() << THROW;
793 }
794 }
795 }
796 }
797 } else {
798 blas::axpy(m.size(), m_.scale, &m_.m[0], 1, &m[0], 1);
799 }
800 return *this;
801 }
802
803 Matrix& operator=(
804 const Matrix<T, Sum<Msym_compressed_col_st_constref, Msym_compressed_col_st_constref>>&
805 m_) {
806 if (m_.size1() != m_.size2()) { UnimplementedError() << THROW; }
807 if (!std::equal(m_.m1.si, m_.m1.si + m_.m1.s2 + 1, m_.m2.si)
808 || !std::equal(
809 m_.m1.index + m_.m1.si[0], m_.m1.index + m_.m1.si[m_.m1.s2],
810 m_.m2.index + m_.m2.si[0])) {
812 }
813 value.clear();
814 si.clear();
815 si.insert(si.begin(), m_.m1.si, m_.m1.si + m_.m1.s2 + 1);
816 index.clear();
817 index.insert(index.begin(), m_.m1.index + m_.m1.si[0], m_.m1.index + m_.m1.si[m_.m1.s2]);
818 m.resize(index.size());
819 for (size_t i = 0; i != m.size(); ++i) {
820 m[i] = m_.scale * (m_.m1.scale * m_.m1.m[i] + m_.m2.scale * m_.m2.m[i]);
821 }
822 return *this;
823 }
824
825 Matrix& operator*=(T s) {
826 value_to_ccarray();
827 blas::scal(m.size(), s, &m[0], 1);
828 return *this;
829 }
830
831 template <typename STORAGE>
832 void scale(const Vector<T, STORAGE>& v_) {
833 value_to_ccarray();
834 size_t i = si[0];
835 for (size_t j = 1; j != si.size(); ++j) {
836 const size_t i_end = si[j];
837 for (; i != i_end; ++i) { m[i] *= v_[j] * v_[index[i]]; }
838 }
839 }
840
841 Vector<T, Vindex1_constref> get_diagonal() {
842 value_to_ccarray();
843 return Vector<T, Vindex1_constref>(si.size() - 1, &m[0], si.back(), &si[0]);
844 }
845
846 void get_diagonal(Vector<T>& diag) {
847 value_to_ccarray();
848 diag.resize(si.size() - 1);
849 for (size_t j = 0; j != diag.size(); ++j) { diag[j] = m[si[j]]; }
850 }
851
852 Matrix<T, Msym_compressed_col_update_sub_ref> operator()(const Interval& i, const Interval& j) {
853 return Matrix<T, Msym_compressed_col_update_sub_ref>(*this, i, j);
854 }
855
856 operator const Matrix<T, Msym_compressed_col_st_constref>() const {
857 const_cast<Matrix*>(this)->value_to_ccarray();
858 return Matrix<T, Msym_compressed_col_st_constref>(
859 si.size() - 1, si.size() - 1, m.size(), &si[0], &index[0], &m[0], 1);
860 }
861
862 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
863 const_cast<Matrix&>(m).value_to_ccarray();
864 l << "symmetric column compressed matrix of size (" << m.size1() << ", " << m.size2()
865 << ") ";
866 l.write(m.si.size(), &m.si[0], 1, "colind");
867 l << ", ";
868 l.write(m.index.size(), &m.index[0], 1, "rowind");
869 l << ", ";
870 l.write(m.m.size(), &m.m[0], 1, "value");
871 return l;
872 }
873
874 friend std::ostream& operator<<(std::ostream& out, const Matrix& m) {
875 const_cast<Matrix&>(m).value_to_ccarray();
876 out << "{" << std::setprecision(15);
877 size_t i = m.si[0];
878 for (size_t j = 0; j != m.si.size() - 1; ++j) {
879 for (size_t i_end = m.si[j + 1]; i != i_end; ++i) {
880 if (m.m[i] != 0) { out << "(" << m.index[i] << ", " << j << "):" << m.m[i] << ","; }
881 }
882 }
883 out << "}";
884
885 /*
886 std::vector<size_t> sii(m.si);
887 const size_t s2 = sii.size() - 1;
888 out << "(";
889 for (size_t i = 0;;) {
890 out << "(";
891 for (size_t j = 0;;) {
892 if (sii[j] == m.si[j + 1] || m.index[sii[j]] != i)
893 out << "0.0";
894 else
895 out << m.m[sii[j]++];
896 if (++j != s2)
897 out << ", ";
898 else
899 break;
900 }
901 out << ")";
902 if (++i != m.s1)
903 out << "," << std::endl;
904 else
905 break;
906 }
907 out << ")";
908 */
909 return out;
910 }
911
912 size_t get_null_space_size() {
913 if (si.size() <= 1) { return 0; }
914 if (solver == 0) { return 0; }
915 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv>*>(this);
916 return noconst_this->solver->get_null_space_size();
917 }
918
919 void get_null_space(Matrix<T, Mrectangle_ref> nks) {
920 if (si.size() <= 1) { return; }
921 if (solver == 0) { return; }
922 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv>*>(this);
923 noconst_this->solver->get_null_space(nks.size1(), nks.size2(), nks.m, nks.size1());
924 }
925
926 void remove_zero(const double tol = 0) {
927 value_to_ccarray();
928 size_t i = si[0];
929 size_t i_out = i;
930 for (size_t j = 1; j != si.size(); ++j) {
931 for (; i != si[j]; ++i) {
932 if (b2000::norm(m[i]) > tol) {
933 m[i_out] = m[i];
934 index[i_out] = index[i];
935 ++i_out;
936 }
937 }
938 si[j] = i_out;
939 }
940 index.resize(i_out);
941 m.resize(i_out);
942 }
943
944 static Matrix null;
945
946private:
947 bool value_to_ccarray() {
948 if (value.empty()) {
949 if (si.empty()) { si.push_back(0); }
950 return false;
951 }
952 if (si.empty()) {
953 si.reserve(value.size() + 1);
954 si.push_back(0);
955 typename std::vector<std::vector<std::pair<size_t, T>>>::const_iterator begin =
956 value.begin();
957 typename std::vector<std::vector<std::pair<size_t, T>>>::const_iterator end =
958 value.end();
959 size_t nnz = 0;
960 for (; begin != end; ++begin) {
961 nnz += begin->size();
962 if (begin->empty()) { ++nnz; }
963 }
964 index.reserve(nnz);
965 m.reserve(nnz);
966 for (begin = value.begin(); begin != end; ++begin) {
967 if (begin->empty()) {
968 index.push_back(begin - value.begin());
969 m.push_back(0);
970 } else {
971 typename std::vector<std::pair<size_t, T>>::const_iterator i = begin->begin();
972 typename std::vector<std::pair<size_t, T>>::const_iterator i_end = begin->end();
973 for (; i != i_end; ++i) {
974 index.push_back(i->first);
975 m.push_back(i->second);
976 }
977 }
978 si.push_back(m.size());
979 }
980 } else {
981 size_t nnz = 0;
982 for (size_t j = 0; j != value.size(); ++j) {
983 nnz += si[j + 1] - si[j] + value[j].size();
984 }
985 std::vector<size_t> si_tmp;
986 si_tmp.reserve(si.size());
987 si_tmp.push_back(0);
988 std::vector<size_t> index_tmp;
989 index_tmp.reserve(nnz);
990 std::vector<T> m_tmp;
991 m_tmp.reserve(nnz);
992 for (size_t j = 0; j != value.size(); ++j) {
993 size_t i = si[j];
994 const size_t i_end = si[j + 1];
995 if (!value[j].empty()) {
996 typename std::vector<std::pair<size_t, T>>::const_iterator iv =
997 value[j].begin();
998 typename std::vector<std::pair<size_t, T>>::const_iterator iv_end =
999 value[j].end();
1000 for (;;) {
1001 if (i == i_end || iv->first < index[i]) {
1002 index_tmp.push_back(iv->first);
1003 m_tmp.push_back(iv->second);
1004 if (++iv == iv_end) { break; }
1005 } else {
1006 index_tmp.push_back(index[i]);
1007 m_tmp.push_back(m[i]);
1008 ++i;
1009 }
1010 }
1011 }
1012 index_tmp.insert(index_tmp.end(), index.begin() + i, index.begin() + i_end);
1013 m_tmp.insert(m_tmp.end(), m.begin() + i, m.begin() + i_end);
1014 si_tmp.push_back(m_tmp.size());
1015 }
1016 si.swap(si_tmp);
1017 index.swap(index_tmp);
1018 m.swap(m_tmp);
1019 delete solver;
1020 solver = 0;
1021 value.clear();
1022 return true;
1023 }
1024 value.clear();
1025 return false;
1026 }
1027
1028 void resolve(
1029 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx, char left_or_right,
1030 Matrix<T, Mrectangle>& null_space, ssize_t max_null_space_vector) const {
1031 if (s == 0) { return; }
1032 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv>*>(this);
1033 noconst_this->value_to_ccarray();
1034 try {
1035 if (solver == 0) {
1036 noconst_this->solver =
1037 LDLt_sparse_solver<T>::new_default(connectivity, *dictionary);
1038 noconst_this->solver->init(
1039 si.size() - 1, index.size(), &si[0], &index[0], &m[0], connectivity,
1040 *dictionary);
1041 }
1042 noconst_this->solver->resolve(s, nrhs, b, ldb, x, ldx, left_or_right);
1043 } catch (SingularMatrixError& e) {
1044 if (max_null_space_vector != 0) {
1045 const size_t nbnv =
1046 max_null_space_vector > 0
1047 && ssize_t(e.null_space_size) > max_null_space_vector
1048 ? max_null_space_vector
1049 : e.null_space_size;
1050 null_space.resize(s, nbnv);
1051 noconst_this->solver->get_null_space(s, nbnv, &null_space(0, 0), s);
1052 }
1053 throw e;
1054 }
1055 const size_t nss = noconst_this->solver->get_null_space_size();
1056 if (max_null_space_vector != 0 && nss > 0) {
1057 const size_t nbnv = max_null_space_vector > 0 && ssize_t(nss) > max_null_space_vector
1058 ? max_null_space_vector
1059 : nss;
1060 null_space.resize(s, nbnv);
1061 noconst_this->solver->get_null_space(s, nbnv, &null_space(0, 0), s);
1062 }
1063 }
1064
1065 void add_colomn(
1066 size_t col, typename std::vector<std::pair<size_t, T>>::const_iterator begin,
1067 typename std::vector<std::pair<size_t, T>>::const_iterator end) {
1068 if (begin == end) { return; }
1069
1070 if (si.empty()) {
1071 std::vector<std::pair<size_t, T>>& vcol = value[col];
1072 if (vcol.empty() || begin->first > vcol.back().first) {
1073 vcol.insert(vcol.end(), begin, end);
1074 } else {
1075 std::vector<std::pair<size_t, T>> tmp;
1076 tmp.reserve(vcol.size() + (end - begin));
1077 typename std::vector<std::pair<size_t, T>>::const_iterator vbegin = vcol.begin();
1078 typename std::vector<std::pair<size_t, T>>::const_iterator vend = vcol.end();
1079 while (vbegin != vend && begin != end) {
1080 if (vbegin->first < begin->first) {
1081 tmp.push_back(*vbegin++);
1082 } else if (vbegin->first > begin->first) {
1083 tmp.push_back(*begin++);
1084 } else {
1085 tmp.push_back(
1086 std::pair<size_t, T>(vbegin->first, vbegin->second + begin->second));
1087 ++begin;
1088 ++vbegin;
1089 }
1090 }
1091 tmp.insert(tmp.end(), vbegin, vend);
1092 tmp.insert(tmp.end(), begin, end);
1093 vcol.swap(tmp);
1094 }
1095 } else {
1096 size_t colind = si[col];
1097 T* beginv = &m[colind];
1098 size_t* begini = &index[colind];
1099 size_t* begini_end = &index[si[col + 1]];
1100 while (begini != begini_end) {
1101 if (*begini == begin->first) {
1102 *beginv += begin->second;
1103 if (++begin == end) { break; }
1104 }
1105 ++begini;
1106 ++beginv;
1107 }
1108 if (begin == end) { return; }
1109 {
1110 if (value.empty()) { value.resize(si.size() - 1); }
1111 std::vector<std::pair<size_t, T>>& vcol = value[col];
1112 beginv = &m[colind];
1113 begini = &index[colind];
1114 if (vcol.empty() || begin->first > vcol.back().first) {
1115 while (begin != end) {
1116 if (begini == begini_end || *begini > begin->first) {
1117 vcol.push_back(*begin++);
1118 } else {
1119 if (*begini == begin->first) { *beginv += (begin++)->second; }
1120 ++begini;
1121 ++beginv;
1122 }
1123 }
1124 } else {
1125 std::vector<std::pair<size_t, T>> tmp;
1126 tmp.reserve(vcol.size() + (end - begin));
1127 typename std::vector<std::pair<size_t, T>>::const_iterator vbegin =
1128 vcol.begin();
1129 typename std::vector<std::pair<size_t, T>>::const_iterator vend = vcol.end();
1130 while (begin != end) {
1131 if (begini == begini_end || *begini > begin->first) {
1132 while (vbegin != vend && vbegin->first < begin->first) {
1133 tmp.push_back(*vbegin++);
1134 }
1135 if (vbegin != vend) {
1136 if (vbegin->first > begin->first) {
1137 tmp.push_back(*begin);
1138 } else {
1139 tmp.push_back(std::pair<size_t, T>(
1140 vbegin->first, vbegin->second + begin->second));
1141 ++vbegin;
1142 }
1143 } else {
1144 tmp.push_back(*begin);
1145 }
1146 ++begin;
1147 } else {
1148 if (*begini == begin->first) { *beginv += (begin++)->second; }
1149 ++begini;
1150 ++beginv;
1151 }
1152 }
1153 tmp.insert(tmp.end(), vbegin, vend);
1154 vcol.swap(tmp);
1155 }
1156 }
1157 }
1158 }
1159
1160 std::vector<size_t> si;
1161 std::vector<T> m;
1162 std::vector<size_t> index;
1163 std::vector<std::vector<std::pair<size_t, T>>>
1164 value;
1167 LDLt_sparse_solver<T>* solver;
1168 SparseMatrixConnectivityType connectivity;
1169 const Dictionary* dictionary;
1170 MVFRIEND;
1171};
1172
1173template <typename T>
1174Matrix<T, Msym_compressed_col_update_inv> Matrix<T, Msym_compressed_col_update_inv>::null;
1175
1176struct Msym_compressed_col_update_inv_ext {
1177 typedef Msym_compressed_col_update_inv_ext const_base;
1178 typedef Msym_compressed_col_update_inv_ext copy;
1179 typedef Msym_compressed_col_update_inv_ext inverse;
1180};
1181
1188template <typename T>
1189class Matrix<T, Msym_compressed_col_update_inv_ext>
1190 : public Matrix<T, Msym_compressed_col_update_inv> {
1191public:
1192 Matrix(
1193 size_t s1_ = 0, size_t size_ext_ = 0,
1194 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
1195 const Dictionary& dictionary_ = Dictionary::get_empty())
1196 : Matrix<T, Msym_compressed_col_update_inv>(s1_, connectivity_, dictionary_),
1197 size_ext(size_ext_),
1198 m_ab(2 * s1_ * size_ext_) {
1199 if (size_ext_ > 1) { UnimplementedError() << THROW; }
1200 }
1201
1202 Matrix(const Matrix& m_) : size_ext(m_.size_ext) {}
1203
1204 std::pair<size_t, size_t> size() const {
1205 return std::pair<size_t, size_t>(
1206 Matrix<T, Msym_compressed_col_update_inv>::size1() + size_ext,
1207 Matrix<T, Msym_compressed_col_update_inv>::size2() + size_ext);
1208 }
1209
1210 size_t size1() const { return Matrix<T, Msym_compressed_col_update_inv>::size1() + size_ext; }
1211
1212 size_t size2() const { return Matrix<T, Msym_compressed_col_update_inv>::size2() + size_ext; }
1213
1214 void resize(
1215 size_t s, size_t s_ext,
1216 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
1217 const Dictionary& dictionary_ = Dictionary::get_empty()) {
1218 Matrix<T, Msym_compressed_col_update_inv>::resize(s, connectivity_, dictionary_);
1219 size_ext = s_ext;
1220 m_ab.resize(s * 2 * size_ext);
1221 if (size_ext != 1) { UnimplementedError() << THROW; }
1222 }
1223
1224 void set_zero() { Matrix<T, Msym_compressed_col_update_inv>::set_zero(); }
1225
1226 void set_zero_same_struct() {
1227 Matrix<T, Msym_compressed_col_update_inv>::set_zero_same_struct();
1228 }
1229
1230 bool is_null() const { return this == &null; }
1231
1232 T operator()(size_t i, size_t j) const {
1233 if (i < Matrix<T, Msym_compressed_col_update_inv>::size1()
1234 && j < Matrix<T, Msym_compressed_col_update_inv>::size2()) {
1235 return Matrix<T, Msym_compressed_col_update_inv>::operator()(i, j);
1236 }
1237 return 0;
1238 }
1239
1240 Matrix<T, Msym_compressed_col_update_sub_ref> operator()(const Interval& i, const Interval& j) {
1241 return Matrix<T, Msym_compressed_col_update_sub_ref>(*this, i, j);
1242 }
1243
1244 void resolve(
1245 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx, const T* ma, const T* mb,
1246 const T* mc, char left_or_right, Matrix<T, Mrectangle>& null_space,
1247 ssize_t max_null_space_vector) const {
1248 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv_ext>*>(this);
1249 if (noconst_this->value_to_ccarray()) {
1250 delete noconst_this->solver;
1251 noconst_this->solver = 0;
1252 }
1253 try {
1254 if (this->solver == 0) {
1255 noconst_this->solver = LDLt_sparse_solver<T>::new_default(
1256 Matrix<T, Msym_compressed_col_update_inv>::connectivity,
1257 *Matrix<T, Msym_compressed_col_update_inv>::dictionary);
1258 noconst_this->solver->init(
1259 Matrix<T, Msym_compressed_col_update_inv>::si.size() - 1,
1260 Matrix<T, Msym_compressed_col_update_inv>::index.size(),
1261 &Matrix<T, Msym_compressed_col_update_inv>::si[0],
1262 &Matrix<T, Msym_compressed_col_update_inv>::index[0],
1263 &Matrix<T, Msym_compressed_col_update_inv>::m[0],
1264 Matrix<T, Msym_compressed_col_update_inv>::connectivity,
1265 *Matrix<T, Msym_compressed_col_update_inv>::dictionary);
1266 }
1267
1268 if (mc != 0) {
1269 std::copy(ma, ma + s - 1, const_cast<T*>(&m_ab[0]));
1270 std::copy(mb, mb + s - 1, const_cast<T*>(&m_ab[s - 1]));
1271 noconst_this->solver->resolve(
1272 s - 1, 2, &m_ab[0], s - 1, const_cast<T*>(&m_ab[0]), s - 1);
1273 const_cast<T&>(div) = 1 / (*mc - blas::dot(s - 1, ma, 1, &m_ab[s - 1], 1));
1274 }
1275
1276 for (size_t i = 0; i != nrhs; ++i) {
1277 const double x2 = x[ldx * i + s - 1] =
1278 div
1279 * (b[ldb * i + s - 1] - blas::dot(s - 1, b + ldb * i, 1, &m_ab[s - 1], 1));
1280 noconst_this->solver->resolve(s - 1, 1, b + ldb * i, ldb, x + ldx * i, ldx);
1281 blas::axpy(s - 1, -x2, &m_ab[0], 1, x + ldx * i, 1);
1282 }
1283
1284 // noconst_this->solver->resolve(s, nrhs, b, ldb, x, ldx,
1285 // ma, mb, mc, ' ');
1286 } catch (SingularMatrixError& e) {
1287 if (max_null_space_vector != 0) {
1288 const size_t nbnv =
1289 max_null_space_vector > 0
1290 && ssize_t(e.null_space_size) > max_null_space_vector
1291 ? max_null_space_vector
1292 : e.null_space_size;
1293 null_space.resize(s, nbnv);
1294 noconst_this->solver->get_null_space(s, nbnv, &null_space(0, 0), s);
1295 }
1296 throw;
1297 }
1298 const size_t nss = noconst_this->solver->get_null_space_size();
1299 if (max_null_space_vector != 0 && nss > 0) {
1300 const size_t nbnv = max_null_space_vector > 0 && ssize_t(nss) > max_null_space_vector
1301 ? max_null_space_vector
1302 : nss;
1303 null_space.resize(s, nbnv);
1304 noconst_this->solver->get_null_space(s, nbnv, &null_space(0, 0), s);
1305 }
1306 }
1307
1308 size_t get_null_space_size() {
1309 if (Matrix<T, Msym_compressed_col_update_inv>::si.size() <= 1) { return 0; }
1310 if (this->solver == 0) { return 0; }
1311 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv_ext>*>(this);
1312 return noconst_this->solver->get_null_space_size();
1313 }
1314
1315 void get_null_space(Matrix<T, Mrectangle_ref> nks) {
1316 if (Matrix<T, Msym_compressed_col_update_inv>::si.size() <= 1) { return; }
1317 if (this->solver == 0) { return; }
1318 Matrix* noconst_this = const_cast<Matrix<T, Msym_compressed_col_update_inv_ext>*>(this);
1319 noconst_this->solver->get_null_space(nks.size1(), nks.size2(), nks.m, nks.size1());
1320 }
1321
1322 static Matrix null;
1323
1324private:
1325 size_t size_ext;
1326 std::vector<double> m_ab;
1327 double div;
1328 MVFRIEND;
1329};
1330
1331template <typename T>
1332Matrix<T, Msym_compressed_col_update_inv_ext> Matrix<T, Msym_compressed_col_update_inv_ext>::null;
1333
1334struct Msym_compressed_col_update_sub_ref {
1335 typedef Mlower_packed copy;
1336};
1337
1338template <typename T>
1339class Matrix<T, Msym_compressed_col_update_sub_ref> {
1340public:
1341 Matrix(Matrix<T, Msym_compressed_col_update_inv>& m_, const Interval& i_, const Interval& j_)
1342 : m(m_), i(i_), j(j_) {}
1343
1344 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(i.size(), j.size()); }
1345
1346 size_t size1() const { return i.size(); }
1347
1348 size_t size2() const { return j.size(); }
1349
1350 Matrix& operator+=(const Matrix<T, Mcompressed_col_constref>& m_) {
1351 if (size() != m_.size()) {
1352 Exception() << "The two matrix do not have the same size, " << size() << " and "
1353 << m_.size() << "." << THROW;
1354 }
1355
1356 if (i.end <= j.start) {
1357 // Only the lower part of the matrix is stored and must by updated
1358 return *this;
1359 }
1360
1361 std::vector<std::pair<size_t, T>> res;
1362 size_t ii = m_.si[0];
1363 for (size_t jj = 0; jj != m_.size2(); ++jj) {
1364 const size_t ii_end = m_.si[jj + 1];
1365 res.clear();
1366 res.reserve(ii_end - ii);
1367 for (; ii != ii_end; ++ii) {
1368 if (i[0] + m_.index[ii] >= j[0] + jj) {
1369 res.push_back(std::pair<size_t, T>(i[0] + m_.index[ii], m_.m[ii]));
1370 }
1371 }
1372 m.add_colomn(j[0] + jj, res.begin(), res.end());
1373 }
1374 return *this;
1375 }
1376
1377 Matrix& operator+=(
1378 const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
1379 if (size() != m_.size()) {
1380 Exception() << "The two matrix do not have the same size, " << size() << " and "
1381 << m_.size() << "." << THROW;
1382 }
1383
1384 if (i.end < j.start) {
1385 // Only the lower part of the matrix is stored and must by updated
1386 return *this;
1387 }
1388
1389 if (!(m_.trans || m_.m1.trans || m_.m2.trans)) {
1390 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
1391 const size_t end_list_flag = m_.m1.size1();
1392 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
1393
1394 const size_t* b_colind_begin = m_.m2.si;
1395 const size_t* const b_colind_end = b_colind_begin + m_.m2.size2();
1396 size_t end_list = end_list_flag;
1397 size_t col = j[0];
1398 while (b_colind_begin != b_colind_end) {
1399 const size_t* b_rowind_begin = &m_.m2.index[*b_colind_begin];
1400 const T* b_value_begin = &m_.m2.m[*b_colind_begin];
1401 const size_t* const b_rowind_end = &m_.m2.index[*++b_colind_begin];
1402 while (b_rowind_begin != b_rowind_end) {
1403 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
1404 const size_t* const a_rowind_end = m_.m1.index + m_.m1.si[*b_rowind_begin + 1];
1405 const T* a_value_begin = m_.m1.m + m_.m1.si[*b_rowind_begin++];
1406 const T b_value_begin_v = *b_value_begin++;
1407 while (a_rowind_begin != a_rowind_end) {
1408 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
1409 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
1410 tmp_index[*a_rowind_begin] = end_list;
1411 end_list = *a_rowind_begin;
1412 }
1413 ++a_rowind_begin;
1414 }
1415 }
1416 std::vector<std::pair<size_t, T>> res_tmp;
1417 while (end_list != end_list_flag) {
1418 res_tmp.push_back(std::pair<size_t, T>(i[end_list], tmp_value[end_list]));
1419 const size_t end_list_next = tmp_index[end_list];
1420 tmp_index[end_list] = std::numeric_limits<size_t>::max();
1421 tmp_value[end_list] = T(0);
1422 end_list = end_list_next;
1423 }
1424 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
1425 m.add_colomn(col++, res_tmp.begin(), res_tmp.end());
1426 }
1427 } else if (!m_.trans && m_.m1.trans && m_.m2.trans) {
1428 std::vector<std::vector<std::pair<size_t, T>>> res_tmp(j.size());
1429
1430 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m2.size2());
1431 const size_t end_list_flag = m_.m2.size2();
1432 T* tmp_value = TemporaryBuffer<T>::get(m_.m2.size2());
1433
1434 const size_t* b_colind_begin = m_.m1.si;
1435 const size_t* const b_colind_end = b_colind_begin + m_.m1.size1();
1436 size_t end_list = end_list_flag;
1437 size_t col = 0;
1438 while (b_colind_begin != b_colind_end) {
1439 const size_t* b_rowind_begin = &m_.m1.index[*b_colind_begin];
1440 const T* b_value_begin = &m_.m1.m[*b_colind_begin];
1441 const size_t* const b_rowind_end = &m_.m1.index[*++b_colind_begin];
1442 while (b_rowind_begin != b_rowind_end) {
1443 const size_t* a_rowind_begin = m_.m2.index + m_.m2.si[*b_rowind_begin];
1444 const size_t* const a_rowind_end = m_.m2.index + m_.m2.si[*b_rowind_begin + 1];
1445 const T* a_value_begin = m_.m2.m + m_.m2.si[*b_rowind_begin++];
1446 const T b_value_begin_v = *b_value_begin++;
1447 while (a_rowind_begin != a_rowind_end) {
1448 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
1449 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
1450 tmp_index[*a_rowind_begin] = end_list;
1451 end_list = *a_rowind_begin;
1452 }
1453 ++a_rowind_begin;
1454 }
1455 }
1456 while (end_list != end_list_flag) {
1457 res_tmp[end_list].push_back(std::pair<size_t, T>(i[col], tmp_value[end_list]));
1458 const size_t end_list_next = tmp_index[end_list];
1459 tmp_index[end_list] = std::numeric_limits<size_t>::max();
1460 tmp_value[end_list] = T(0);
1461 end_list = end_list_next;
1462 }
1463 ++col;
1464 }
1465 for (size_t jj = 0; jj != res_tmp.size(); ++jj) {
1466 if (!res_tmp[jj].empty()) {
1467 std::sort(res_tmp[jj].begin(), res_tmp[jj].end(), CompareFirstOfPair());
1468 m.add_colomn(j[jj], res_tmp[jj].begin(), res_tmp[jj].end());
1469 }
1470 }
1471 } else if (!m_.trans && !m_.m1.trans && m_.m2.trans && m_.m1.m == m_.m2.m) {
1472 Matrix<T, Mcompressed_col> m_m2;
1473 m_m2 = m_.m2;
1474
1475 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
1476 const size_t end_list_flag = m_.m1.size1();
1477 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
1478
1479 T scale = m_.scale * m_.m1.scale;
1480 const size_t* b_colind_begin = &m_m2.si[0];
1481 const size_t* const b_colind_end = b_colind_begin + m_m2.size2();
1482 size_t end_list = end_list_flag;
1483 size_t col = 0;
1484 while (b_colind_begin != b_colind_end) {
1485 const size_t* b_rowind_begin = &m_m2.index[*b_colind_begin];
1486 const T* b_value_begin = &m_m2.m[*b_colind_begin];
1487 const size_t* const b_rowind_end = &m_m2.index[*++b_colind_begin];
1488 while (b_rowind_begin != b_rowind_end) {
1489 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
1490 const size_t* const a_rowind_end =
1491 m_.m1.index + m_.m1.si[*b_rowind_begin++ + 1];
1492 while (a_rowind_begin != a_rowind_end && *a_rowind_begin < col) {
1493 ++a_rowind_begin;
1494 }
1495 const T* a_value_begin = m_.m1.m + (a_rowind_begin - m_.m1.index);
1496 const T b_value_begin_v = *b_value_begin++;
1497 while (a_rowind_begin != a_rowind_end) {
1498 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
1499 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
1500 tmp_index[*a_rowind_begin] = end_list;
1501 end_list = *a_rowind_begin;
1502 }
1503 ++a_rowind_begin;
1504 }
1505 }
1506 std::vector<std::pair<size_t, T>> res_tmp;
1507 while (end_list != end_list_flag) {
1508 res_tmp.push_back(
1509 std::pair<size_t, T>(i[end_list], scale * tmp_value[end_list]));
1510 const size_t end_list_next = tmp_index[end_list];
1511 tmp_index[end_list] = std::numeric_limits<size_t>::max();
1512 tmp_value[end_list] = T(0);
1513 end_list = end_list_next;
1514 }
1515
1516 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
1517 m.add_colomn(j[col++], res_tmp.begin(), res_tmp.end());
1518 }
1519 } else {
1521 }
1522
1523 return *this;
1524 }
1525
1526private:
1527 Matrix<T, Msym_compressed_col_update_inv>& m;
1528 const Interval& i;
1529 const Interval& j;
1530 MVFRIEND;
1531};
1532
1533} // namespace b2000::b2linalg
1534
1535#endif
#define THROW
Definition b2exception.H:198
Definition b2dictionary.H:48
static Dictionary & get_empty()
Definition b2dictionary.C:78
static T * get(size_t size)
Definition b2linear_algebra_utils.H:50
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314