b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2matrix_compressed.H
1//------------------------------------------------------------------------
2// b2matrix_compressed.H --
3//
4// A framework for generic linear algebraic (matrix) computations.
5//
6// written by Mathias Doreille
7// Thomas Blome <thomas.blome@dlr.de>
8//
9// Copyright (c) 2004-2012,2016,2017 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_COMPRESSED_H__
19#define __B2MATRIX_COMPRESSED_H__
20
21#include <cassert>
22#include <map>
23#include <set>
24#include <vector>
25
26#include "b2linear_algebra_def.H"
27#include "b2sparse_solver.H"
28#include "b2vector_compressed.H"
29#include "b2vector_dense.H"
30#include "b2vector_index.H"
31#include "utils/b2dictionary.H"
32#include "utils/b2util.H"
33
34namespace b2000::b2linalg {
35
36struct Mcompressed_col {
37 using base = Mcompressed_col_ref;
38 using const_base = Mcompressed_col_st_constref;
39 using copy = Mcompressed_col;
40};
41
42template <typename T>
43class Matrix<T, Mcompressed_col> {
44public:
45 Matrix() : s1(0) { si.assign(1, 0); }
46
47 Matrix(size_t s1_, size_t s2_, size_t snn_) : s1(s1_), si(s2_ + 1), m(snn_), index(snn_) {}
48
49 Matrix(const Matrix& m_) : s1(m_.s1), si(m_.si), m(m_.m), index(m_.index) {}
50
51 template <typename T1>
52 Matrix(const Matrix<T1, Mcompressed_col>& m_, bool set_zero_same_structure = false)
53 : s1(m_.s1), si(m_.si), m(m_.m.begin(), m_.m.end()), index(m_.index) {}
54
55 template <typename T1>
56 Matrix& operator=(const Matrix<T1, Mcompressed_col>& m_) {
57 s1 = m_.s1;
58 si = m_.si;
59 m.assign(m_.m.begin(), m_.m.end());
60 index = m_.index;
61 return *this;
62 }
63
64 template <typename T1>
65 Matrix& operator=(const Matrix<T1, Msym_compressed_col_st_constref>& m_) {
66 s1 = m_.s1;
67 si.assign(s1 + 2, 0);
68
69 const size_t* m_index = m_.index + m_.si[0];
70 size_t* si1 = &si[0] + 2;
71 for (size_t j = 0; j != s1; ++j) {
72 const size_t* m_index_end = m_.index + m_.si[j + 1];
73 si1[j] += m_index_end - m_index;
74 if (m_index != m_index_end && *m_index == j) { ++m_index; }
75 for (; m_index < m_index_end; ++m_index) { ++si1[*m_index]; }
76 }
77
78 std::partial_sum(si1, si1 + s1, si1);
79
80 --si1;
81 index.assign(si1[s1], 0);
82 m.assign(si1[s1], T(0));
83 size_t i = m_.si[0];
84 for (size_t j = 0; j != s1; ++j) {
85 const size_t i_end = m_.si[j + 1];
86 std::copy(m_.index + i, m_.index + i_end, index.begin() + si1[j]);
87 {
88 const T* b = m_.m + i;
89 const T* b_end = m_.m + i_end;
90 T* bs = &m[si1[j]];
91 for (; b != b_end; ++b, ++bs) { *bs = m_.scale * *b; }
92 }
93 si1[j] += i_end - i;
94 if (i != i_end && m_.index[i] == j) { ++i; }
95 for (; i < i_end; ++i) {
96 size_t& ii = si1[m_.index[i]];
97 index[ii] = j;
98 m[ii] = m_.scale * m_.m[i];
99 ++ii;
100 }
101 }
102
103 si.pop_back();
104 return *this;
105 }
106
107 Matrix(const Matrix<T, Mcompressed_col_st_constref>& m_) { *this = m_; }
108
109 Matrix(const Matrix<T, Msym_compressed_col_st_constref>& m_, const Index& index_) {
110 resize(m_.size1(), index_.size(), 0);
111 std::vector<size_t> ind(index_);
112 std::sort(ind.begin(), ind.end());
113 const size_t s2 = index_.size();
114 size_t ij = 0;
115 for (size_t j = 0; j != m_.s1; ++j) {
116 size_t ii = m_.si[j];
117 const size_t ii_end = m_.si[j + 1];
118 if (ii == ii_end) { continue; }
119 if (ij != s2 && j == ind[ij]) {
120 si[ij] += ii_end - ii;
121 ++ij;
122 }
123 if (m_.index[ii] == j) { ++ii; }
124 size_t i = 0;
125 while (i != s2 && ii != ii_end) {
126 if (m_.index[ii] < ind[i]) {
127 ++ii;
128 } else if (m_.index[ii] > ind[i]) {
129 ++i;
130 } else {
131 ++si[i];
132 ++ii;
133 ++i;
134 }
135 }
136 }
137 for (size_t i = 0; i != s2; ++i) { si[i + 1] += si[i]; }
138 index.assign(si[s2], 0);
139 m.assign(si[s2], 0);
140 for (size_t i = s2; i > 1; --i) { si[i] = si[i - 2]; }
141 si[0] = si[1] = 0;
142 size_t* siptr = &si[1];
143 ij = 0;
144 for (size_t j = 0; j != m_.s1; ++j) {
145 size_t ii = m_.si[j];
146 const size_t ii_end = m_.si[j + 1];
147 if (ii == ii_end) { continue; }
148 if (ij != s2 && j == ind[ij]) {
149 std::copy(m_.index + ii, m_.index + ii_end, &index[siptr[ij]]);
150 std::copy(m_.m + ii, m_.m + ii_end, &m[siptr[ij]]);
151 siptr[ij] += ii_end - ii;
152 ++ij;
153 }
154 if (m_.index[ii] == j) { ++ii; }
155 size_t i = 0;
156 while (i != s2 && ii != ii_end) {
157 if (m_.index[ii] < ind[i]) {
158 ++ii;
159 } else if (m_.index[ii] > ind[i]) {
160 ++i;
161 } else {
162 index[siptr[i]] = j;
163 m[siptr[i]] = m_.m[ii];
164 ++siptr[i];
165 ++ii;
166 ++i;
167 }
168 }
169 }
170 }
171
172 void this_prod_index(Index& i_index) const {
173 const size_t* colind = &si[0];
174 const size_t* rowind = &index[0];
175 std::set<size_t> tmp_rowind;
176 const size_t* const i_end = &i_index[0] + i_index.size();
177 const size_t i_max = si.size() - 1;
178 for (const size_t* i = &i_index[0]; i != i_end; ++i) {
179 if (*i >= i_max) { Exception() << THROW; }
180 tmp_rowind.insert(rowind + colind[*i], rowind + colind[*i + 1]);
181 }
182 i_index.assign(tmp_rowind.begin(), tmp_rowind.end());
183 }
184
185 void remove_row(const Index& index_row) {
186 std::vector<size_t> tmp_index(s1);
187 {
188 size_t ii = 0;
189 size_t i_index = 0;
190 for (size_t i = 0; i != s1; ++i) {
191 if (i_index != index_row.size() && i == index_row[i_index]) {
192 tmp_index[i] = s1;
193 ++i_index;
194 } else {
195 tmp_index[i] = ii++;
196 }
197 }
198 }
199 size_t i_o = si[0];
200 si[0] = 0;
201 size_t i_n = 0;
202 for (size_t j = 1; j != si.size(); ++j) {
203 const size_t i_oe = si[j];
204 for (; i_o != i_oe; ++i_o) {
205 const size_t tmp_i = tmp_index[index[i_o]];
206 if (tmp_i != s1) {
207 index[i_n] = tmp_i;
208 m[i_n] = m[i_o];
209 ++i_n;
210 }
211 }
212 si[j] = i_n;
213 }
214 index.resize(i_n);
215 m.resize(i_n);
216 s1 -= index_row.size();
217 }
218
219 void remove_col(const Index& index_col) {
220 size_t index_col_ptr = 0;
221 size_t si_dest = 0;
222 size_t dest = 0;
223 for (size_t j = 0; j != si.size() - 1; ++j) {
224 if (index_col_ptr != index_col.size() && j == index_col[index_col_ptr]) {
225 ++index_col_ptr;
226 } else {
227 if (dest < si[j]) {
228 std::copy(
229 index.begin() + si[j], index.begin() + si[j + 1], index.begin() + dest);
230 std::copy(m.begin() + si[j], m.begin() + si[j + 1], m.begin() + dest);
231 }
232 const size_t s = si[j + 1] - si[j];
233 si[si_dest++] = dest;
234 dest += s;
235 }
236 }
237 si[si_dest++] = dest;
238 si.resize(si_dest);
239 index.resize(dest);
240 m.resize(dest);
241 }
242
243 void remove_nonzero_in_cols(const Index& index_col) {
244 size_t i_o = si[0];
245 size_t i_n = i_o;
246 size_t jj = 0;
247 for (size_t j = 0; j != index_col.size(); ++j) {
248 const size_t i_l = si[index_col[j]];
249 if (i_n != i_o) {
250 std::copy(index.begin() + i_o, index.begin() + i_l, index.begin() + i_n);
251 std::copy(m.begin() + i_o, m.begin() + i_l, m.begin() + i_n);
252 const size_t diff = i_o - i_n;
253 for (; jj != index_col[j]; ++jj) { si[jj] -= diff; }
254 }
255 i_n += i_l - i_o;
256 i_o = si[index_col[j] + 1];
257 }
258 if (i_n != i_o) {
259 const size_t i_l = si.back();
260 std::copy(index.begin() + i_o, index.begin() + i_l, index.begin() + i_n);
261 std::copy(m.begin() + i_o, m.begin() + i_l, m.begin() + i_n);
262 const size_t diff = i_o - i_n;
263 for (; jj != si.size(); ++jj) { si[jj] -= diff; }
264 }
265 }
266
267 bool get_nonzero_unit_row_for_column(const Index& index_col, Index& index_row) {
268 index_row.clear();
269 index_row.reserve(index_col.size());
270 for (size_t j = 0; j != index_col.size(); ++j) {
271 size_t jj = index_col[j];
272 if (si[jj + 1] - si[jj] != 1 || m[si[jj]] != T(1)) { return false; }
273 index_row.push_back(index[si[jj]]);
274 }
275 std::sort(index_row.begin(), index_row.end());
276 return true;
277 }
278
279 Matrix& operator=(const Matrix<T, Mcompressed_col_st_constref>& m_) {
280 s1 = m_.size1();
281 if (!m_.trans) {
282 si.assign(m_.si, m_.si + m_.s2 + 1);
283 index.assign(m_.index, m_.index + m_.si[m_.s2]);
284 if (m_.scale == T(1)) {
285 m.assign(m_.m, m_.m + m_.si[m_.s2]);
286 } else {
287 m.reserve(m_.si[m_.s2]);
288 for (const T* i = m_.m; i != m_.m + m_.si[m_.s2]; ++i) {
289 m.push_back(m_.scale * *i);
290 }
291 }
292 } else {
293 si.assign(m_.s1 + 1, 0);
294 m.assign(m_.si[m_.s2], 0);
295 index.assign(m_.si[m_.s2], 0);
296
297 size_t* tmp_col = new size_t[m_.s1];
298 std::fill_n(tmp_col, m_.s1, 0);
299
300 const size_t* colind_begin = m_.si;
301 const size_t* rowind_begin = m_.index + *colind_begin;
302 const size_t* const colind_end = colind_begin + s1;
303 while (colind_begin != colind_end) {
304 const size_t* const rowind_end = m_.index + *++colind_begin;
305 while (rowind_begin != rowind_end) { ++(tmp_col[*rowind_begin++]); }
306 }
307 si[0] = 0;
308 std::partial_sum(tmp_col, tmp_col + m_.s1, si.begin() + 1);
309
310 rowind_begin = m_.index + m_.si[0];
311 const T* value_begin = m_.m;
312 for (size_t col = 0; col != s1; ++col) {
313 const size_t* const rowind_end = m_.index + m_.si[col + 1];
314 while (rowind_begin != rowind_end) {
315 size_t i = (si[*rowind_begin++])++;
316 index[i] = col;
317 m[i] = m_.scale * *value_begin++;
318 }
319 }
320
321 si[0] = 0;
322 std::partial_sum(tmp_col, tmp_col + m_.s1, si.begin() + 1);
323 delete[] tmp_col;
324 }
325 return *this;
326 }
327
328 Matrix(const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_)
329 : s1(m_.size1()), si(m_.size2() + 1) {
330 *this = m_;
331 }
332
333 Matrix& operator=(
334 const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
335 if (m_.trans || m_.m1.trans || m_.m2.trans) { UnimplementedError() << THROW; }
336
337 s1 = m_.size1();
338 si.resize(m_.size2() + 1);
339 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
340 const size_t end_list_flag = m_.m1.size1();
341 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
342 si[0] = 0;
343
344 T scale = m_.scale * m_.m1.scale * m_.m2.scale;
345
346 {
347 const size_t* b_colind_begin = m_.m2.si;
348 const size_t* const b_colind_end = b_colind_begin + m_.m2.size2();
349 size_t end_list = end_list_flag;
350 size_t col = 0;
351 while (b_colind_begin != b_colind_end) {
352 const size_t* b_rowind_begin = &m_.m2.index[*b_colind_begin];
353 const T* b_value_begin = &m_.m2.m[*b_colind_begin];
354 const size_t* const b_rowind_end = &m_.m2.index[*++b_colind_begin];
355 while (b_rowind_begin != b_rowind_end) {
356 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
357 const size_t* const a_rowind_end = m_.m1.index + m_.m1.si[*b_rowind_begin + 1];
358 const T* a_value_begin = m_.m1.m + m_.m1.si[*b_rowind_begin++];
359 const T b_value_begin_v = *b_value_begin++;
360 while (a_rowind_begin != a_rowind_end) {
361 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
362 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
363 tmp_index[*a_rowind_begin] = end_list;
364 end_list = *a_rowind_begin;
365 }
366 ++a_rowind_begin;
367 }
368 }
369 std::vector<std::pair<size_t, T>> res_tmp;
370 while (end_list != end_list_flag) {
371 res_tmp.push_back(std::pair<size_t, T>(end_list, tmp_value[end_list]));
372 const size_t end_list_next = tmp_index[end_list];
373 tmp_index[end_list] = std::numeric_limits<size_t>::max();
374 tmp_value[end_list] = T(0);
375 end_list = end_list_next;
376 }
377 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
378
379 for (typename std::vector<std::pair<size_t, T>>::iterator i = res_tmp.begin();
380 i != res_tmp.end(); ++i) {
381 index.push_back(i->first);
382 m.push_back(i->second * scale);
383 }
384 si[++col] = m.size();
385 }
386 }
387 return *this;
388 }
389
390 Matrix& operator=(
391 const Matrix<
392 T, Sum<Mcompressed_col_st_constref,
393 MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>>& m_) {
394 if (m_.trans || m_.m1.trans || m_.m2.m1.trans || m_.m2.m2.trans) {
396 }
397
398 s1 = m_.size1();
399 si.resize(m_.size2() + 1);
400 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m2.m1.size1());
401 const size_t end_list_flag = m_.m2.m1.size1();
402 T* tmp_value = TemporaryBuffer<T>::get(m_.m2.m1.size1());
403 si[0] = 0;
404
405 T scale_1 = m_.scale * m_.m1.scale;
406 T scale_2 = m_.scale * m_.m2.scale * m_.m2.m1.scale * m_.m2.m2.scale;
407
408 {
409 const size_t* c_colind_begin = m_.m1.si;
410 const size_t* b_colind_begin = m_.m2.m2.si;
411 const size_t* const b_colind_end = b_colind_begin + m_.m2.m2.size2();
412 size_t end_list = end_list_flag;
413 size_t col = 0;
414 while (b_colind_begin != b_colind_end) {
415 const size_t* b_rowind_begin = &m_.m2.m2.index[*b_colind_begin];
416 const T* b_value_begin = &m_.m2.m2.m[*b_colind_begin];
417 const size_t* b_rowind_end = &m_.m2.m2.index[*++b_colind_begin];
418 while (b_rowind_begin != b_rowind_end) {
419 const size_t* a_rowind_begin = m_.m2.m1.index + m_.m2.m1.si[*b_rowind_begin];
420 const size_t* const a_rowind_end =
421 m_.m2.m1.index + m_.m2.m1.si[*b_rowind_begin + 1];
422 const T* a_value_begin = m_.m2.m1.m + m_.m2.m1.si[*b_rowind_begin++];
423 const T b_value_begin_v = *b_value_begin++;
424 while (a_rowind_begin != a_rowind_end) {
425 tmp_value[*a_rowind_begin] += scale_2 * *a_value_begin++ * b_value_begin_v;
426 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
427 tmp_index[*a_rowind_begin] = end_list;
428 end_list = *a_rowind_begin;
429 }
430 ++a_rowind_begin;
431 }
432 }
433
434 b_rowind_begin = &m_.m1.index[*c_colind_begin];
435 b_value_begin = &m_.m1.m[*c_colind_begin];
436 b_rowind_end = &m_.m1.index[*++c_colind_begin];
437 while (b_rowind_begin != b_rowind_end) {
438 tmp_value[*b_rowind_begin] += scale_1 * *b_value_begin++;
439 if (!(std::numeric_limits<size_t>::max() - tmp_index[*b_rowind_begin])) {
440 tmp_index[*b_rowind_begin] = end_list;
441 end_list = *b_rowind_begin;
442 }
443 ++b_rowind_begin;
444 }
445
446 std::vector<std::pair<size_t, T>> res_tmp;
447 while (end_list != end_list_flag) {
448 res_tmp.push_back(std::pair<size_t, T>(end_list, tmp_value[end_list]));
449 const size_t end_list_next = tmp_index[end_list];
450 tmp_index[end_list] = std::numeric_limits<size_t>::max();
451 tmp_value[end_list] = T(0);
452 end_list = end_list_next;
453 }
454 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
455
456 for (typename std::vector<std::pair<size_t, T>>::iterator i = res_tmp.begin();
457 i != res_tmp.end(); ++i) {
458 index.push_back(i->first);
459 m.push_back(i->second);
460 }
461 si[++col] = m.size();
462 }
463 }
464 return *this;
465 }
466
467 bool is_null() const { return this == &null; }
468
469 void set_zero() {
470 std::fill(si.begin(), si.end(), 0);
471 index.clear();
472 m.clear();
473 }
474
475 void clear() {
476 s1 = 0;
477 si.clear();
478 index.clear();
479 m.clear();
480 }
481
482 void resize(size_t s1_, size_t s2_) {
483 s1 = s1_;
484 if (size2() < s2_) {
485 si.insert(si.end(), s2_ - size2(), si.back());
486 } else {
487 si.resize(s2_ + 1);
488 }
489 }
490
491 void resize(size_t s1_, size_t s2_, size_t snn) {
492 s1 = s1_;
493 si.assign(s2_ + 1, 0);
494 index.resize(snn);
495 m.resize(snn);
496 }
497
498 void resize(const Index& idx) {
499 s1 = idx.size();
500 if (idx.sorted()) {
501 for (std::vector<size_t>::iterator i = index.begin(); i != index.end(); ++i) {
502 *i = idx[*i];
503 }
504 } else {
505 for (size_t j = 0; j != size2(); ++j) {
506 size_t* i_begin = &index[si[j]];
507 size_t* i_end = &index[si[j + 1]];
508 T* v_begin = &m[si[j]];
509 std::vector<std::pair<size_t, T>> tmp;
510 tmp.reserve(i_end - i_begin);
511 while (i_begin != i_end) {
512 tmp.push_back(std::pair<size_t, T>(idx[*i_begin++], *v_begin++));
513 }
514 std::sort(tmp.begin(), tmp.end(), CompareFirstOfPair());
515 i_begin = &index[si[j]];
516 v_begin = &m[si[j]];
517 for (typename std::vector<std::pair<size_t, T>>::iterator i = tmp.begin();
518 i != tmp.end(); ++i) {
519 *i_begin++ = i->first;
520 *v_begin++ = i->second;
521 }
522 }
523 }
524 }
525
526 size_t get_nb_nonzero() const { return si.back(); }
527
528 size_t get_nb_nonzero(size_t col) const { return si[col + 1] - si[col]; }
529
530 void push_back(size_t row, size_t col, T value) {
531 while (si.size() <= col + 1) { si.push_back(si.back()); }
532 index.push_back(row);
533 m.push_back(value);
534 ++si.back();
535 s1 = std::max(s1, row + 1);
536 }
537
538 void push_back(size_t row, size_t col, const Vector<T, Vdense_constref>& v) {
539 while (si.size() <= col + 1) { si.push_back(si.back()); }
540 m.insert(m.end(), v.v, v.v + v.s);
541 for (size_t i = 0; i != v.s; ++i) { index.push_back(row + i); }
542 si.back() = m.size();
543 s1 = std::max(s1, row + v.s);
544 }
545
546 void push_back(size_t row, size_t col, const Index& ind, const Vector<T, Vdense_constref>& v) {
547 while (si.size() <= col + 1) { si.push_back(si.back()); }
548 for (size_t i = 0; i != v.size(); ++i) {
549 m.push_back(v[i]);
550 index.push_back(row + ind[i]);
551 }
552 si.back() = m.size();
553 s1 = std::max(s1, row + v.s);
554 }
555
556 void push_back(size_t row, size_t col, const Vector<T, Vcompressed_scale_constref>& v) {
557 while (si.size() <= col + 1) { si.push_back(si.back()); }
558 for (size_t i = 0; i != v.snn; ++i) {
559 m.push_back(v.scale * v.v[i]);
560 index.push_back(row + v.index[i]);
561 }
562 si.back() = m.size();
563 s1 = std::max(s1, row + v.s);
564 }
565
566 void push_back(size_t i, const Matrix<T, Mcompressed_col_st_constref>& m_) {
567 if (m_.trans) { UnimplementedError() << THROW; }
568 if (m_.size2() == 0) { return; }
569 if (si.empty()) { si.push_back(0); }
570 std::size_t ii = index.size();
571 index.insert(index.end(), m_.index + m_.si[0], m_.index + m_.si[m_.s2]);
572 for (std::vector<size_t>::iterator iii = index.begin() + ii; iii != index.end(); ++iii) {
573 *iii += i;
574 }
575 size_t j = m.size();
576 m.insert(m.end(), m_.m + m_.si[0], m_.m + m_.si[m_.s2]);
577 if (m_.scale != T(1)) {
578 for (; j != m.size(); ++j) { m[j] *= m_.scale; }
579 }
580
581 size_t is = si.size();
582 si.insert(si.end(), m_.si + 1, m_.si + m_.s2 + 1);
583 size_t iv = si[is - 1] - m_.si[0];
584 for (std::vector<size_t>::iterator iii = si.begin() + is; iii != si.end(); ++iii) {
585 *iii += iv;
586 }
587 s1 = std::max(s1, i + m_.size1());
588 }
589
590 void push_back(
591 size_t i1, const Matrix<T, Mcompressed_col_constref>& m1, size_t i2,
592 const Matrix<T, Mcompressed_col_constref>& m2) {
593 if (i1 + m1.size1() > i2 && m1.size2() != m2.size2()) { UnimplementedError() << THROW; }
594 if (si.empty()) { si.push_back(0); }
595 for (size_t j = 0; j != m1.size2(); ++j) {
596 size_t ii = index.size();
597 index.insert(index.end(), m1.index + m1.si[j], m1.index + m1.si[j + 1]);
598 for (std::vector<size_t>::iterator i = index.begin() + ii; i != index.end(); ++i) {
599 *i += i1;
600 }
601 ii = index.size();
602 index.insert(index.end(), m2.index + m2.si[j], m2.index + m2.si[j + 1]);
603 for (std::vector<size_t>::iterator i = index.begin() + ii; i != index.end(); ++i) {
604 *i += i2;
605 }
606 m.insert(m.end(), m1.m + m1.si[j], m1.m + m1.si[j + 1]);
607 m.insert(m.end(), m2.m + m2.si[j], m2.m + m2.si[j + 1]);
608 si.push_back(m.size());
609 }
610 s1 = std::max(s1, i2 + m2.size1());
611 }
612
613 void set_identity(size_t i1, size_t i2) {
614 s1 = i1;
615 si.resize(i2 + 1);
616 {
617 const size_t s = std::min(i1, i2);
618 index.resize(s);
619 m.resize(s);
620 }
621 size_t i = 0;
622 for (; i != index.size(); ++i) {
623 si[i] = i;
624 index[i] = i;
625 m[i] = 1;
626 }
627 std::fill(si.begin() + i, si.end(), i);
628 }
629
630 void push_back_identity(size_t i1, size_t i2) {
631 if (si.empty()) {
632 index.reserve(std::min(i1, i2));
633 si.reserve(i2 + 1);
634 m.reserve(index.size());
635 si.push_back(0);
636 }
637 while (si.size() < i1 + 1) { si.push_back(si.back()); }
638 while (i1 != i2) {
639 index.push_back(i1);
640 m.push_back(1);
641 si.push_back(m.size());
642 ++i1;
643 }
644 s1 = std::max(s1, i2);
645 }
646
647 void get_values(size_t*& colind, size_t*& rowind, T*& value) {
648 colind = &si[0];
649 rowind = &index[0];
650 value = &m[0];
651 }
652
653 size_t get_col_value(const size_t col, size_t*& rowind, T*& value) {
654 rowind = &index[si[col]];
655 value = &m[si[col]];
656 return si[col + 1] - si[col];
657 }
658
659 void set_value(
660 size_t s1_, size_t s2_, size_t snn, const size_t* colind, const size_t* rowind,
661 const T* value) {
662 s1 = s1_;
663 si.resize(s2_ + 1);
664 std::copy(colind, colind + s2_ + 1, si.begin());
665 index.resize(snn);
666 std::copy(rowind, rowind + snn, index.begin());
667 m.resize(snn);
668 std::copy(value, value + snn, m.begin());
669 }
670
671 std::pair<size_t, size_t> size() const {
672 return std::pair<size_t, size_t>(s1, si.size() == 0 ? 0 : si.size() - 1);
673 }
674
675 size_t size1() const { return s1; }
676
677 size_t size2() const { return si.size() == 0 ? 0 : si.size() - 1; }
678
679 T operator()(size_t i, size_t j) const {
680 std::vector<size_t>::const_iterator s = index.begin() + si[j];
681 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
682 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
683 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
684 return 0;
685 }
686
687 Matrix<T, Msub_constref<Mcompressed_col_constref, Index, Index>> operator()(
688 const Index& i, const Index& j) const {
689 return Matrix<T, Msub_constref<Mcompressed_col_constref, Index, Index>>(
690 Matrix<T, Mcompressed_col_constref>(*this), i, j);
691 }
692
693 Matrix<T, Mcompressed_col_constref> operator()(const Interval& j) const {
694 return Matrix<T, Mcompressed_col_constref>(
695 s1, j.size(), si[j.end] - si[j.start], &si[j.start], &index[0], &m[0]);
696 }
697
698 Vector<T, Vcompressed_scale_constref> operator[](size_t i) const {
699 if (i >= size2()) { Exception() << THROW; }
700 return Vector<T, Vcompressed_scale_constref>(
701 s1, si[i + 1] - si[i], &index[si[i]], &m[si[i]], 1);
702 }
703
704 Matrix& operator=(const Matrix<T, Msub_constref<Mcompressed_col_constref, Index, Index>>& m_) {
705 s1 = m_.size1();
706 si.reserve(m_.size2() + 1);
707 si.push_back(0);
708 const size_t* jindex;
709 const size_t* jindex_end;
710 Index index_tmp;
711 if (m_.index2.is_all()) {
712 index_tmp.resize(m_.m.size1());
713 for (size_t i = 0; i != index_tmp.size(); ++i) { index_tmp[i] = i; }
714 jindex = &index_tmp[0];
715 jindex_end = jindex + index_tmp.size();
716 } else {
717 jindex = &m_.index2[0];
718 jindex_end = jindex + m_.index2.size();
719 }
720 if (m_.index1.is_all()) {
721 for (; jindex != jindex_end; ++jindex) {
722 size_t j = m_.m.si[*jindex];
723 size_t j_end = m_.m.si[*jindex + 1];
724 m.insert(m.end(), m_.m.m + j, m_.m.m + j_end);
725 index.insert(index.end(), m_.m.index + j, m_.m.index + j_end);
726 si.push_back(index.size());
727 }
728 } else {
729 if (m_.index1.sorted()) {
730 Index dual_iindex = m_.index1.make_dual();
731 for (; jindex != jindex_end; ++jindex) {
732 size_t j = m_.m.si[*jindex];
733 size_t j_end = m_.m.si[*jindex + 1];
734 for (; j != j_end; ++j) {
735 if (dual_iindex[m_.m.index[j]] != dual_iindex.size()) {
736 index.push_back(m_.m.index[j]);
737 m.push_back(m_.m.m[j]);
738 }
739 }
740 si.push_back(index.size());
741 }
742 } else {
743 Index dual_iindex = m_.index1.make_dual();
744 for (; jindex != jindex_end; ++jindex) {
745 size_t j = m_.m.si[*jindex];
746 size_t j_end = m_.m.si[*jindex + 1];
747 std::vector<std::pair<size_t, T>> tmp;
748 tmp.reserve(j_end - j);
749 for (; j != j_end; ++j) {
750 tmp.push_back(std::pair<size_t, T>(dual_iindex[m_.m.index[j]], m_.m.m[j]));
751 }
752 std::sort(tmp.begin(), tmp.end(), CompareFirstOfPair());
753 for (typename std::vector<std::pair<size_t, T>>::iterator i = tmp.begin();
754 i != tmp.end(); ++i) {
755 index.push_back(i->first);
756 m.push_back(i->second);
757 }
758 si.push_back(index.size());
759 }
760 }
761 }
762 return *this;
763 }
764
765 void swap(Matrix& m_) {
766 std::swap(s1, m_.s1);
767 si.swap(m_.si);
768 m.swap(m_.m);
769 index.swap(m_.index);
770 }
771
775 void LUFactorization(
776 Matrix<T, Mcompressed_col>& trans_L, Matrix<T, Mcompressed_col>& U, Index& P, Index& Q,
777 Vector<double, Vdense>& R) {
778 Matrix<T, Mcompressed_col_constref>(*this).LUFactorization(trans_L, U, P, Q, R);
779 }
780
790 size_t LUIFactorization(
791 Matrix<T, Mcompressed_col>& L, Matrix<T, Mcompressed_col>& trans_U, Index& P, Index& Q,
792 const bool compute_LU, Vector<double>& w = Vector<double>::null,
793 const bool rook_pivot = false, double tol_pivot = -1, const double tol_drop = 3e-13,
794 const double tol_rank_abs = 3.7e-11, const double tol_rank_rel = 3.7e-11,
795 const Index& col_to_remove = Index::null);
796
800 void LUIFactorization(
801 Matrix<T, Mcompressed_col>& L, Matrix<T, Mcompressed_col>& trans_U, Index& P, Index& Q,
802 const double tol_drop = 3e-13, const double tol_pivot_rank_search = 4.0,
803 const double tol_pivot_LU_fact = 10.0, const double tol_rank_abs = 3.7e-11,
804 const double tol_rank_rel = 3.7e-11) {
805 // rank search
806 Vector<double> w;
807 const size_t rank = LUIFactorization(
808 L, trans_U, Index::null, Index::null, false, w, true, tol_pivot_rank_search, tol_drop,
809 tol_rank_abs, tol_rank_rel);
810 Index col_to_remove;
811 col_to_remove.reserve(w.size() - rank);
812 for (size_t i = 0; i != w.size(); ++i) {
813 if (w[i] <= 0) { col_to_remove.push_back(i); }
814 }
815
816 // LU factorisation
817 LUIFactorization(
818 L, trans_U, P, Q, true, Vector<double>::null, false, tol_pivot_LU_fact, tol_drop,
819 tol_rank_abs, tol_rank_rel, col_to_remove);
820 }
821
825 void get_dep_columns(
826 Index& Q, const double tol_drop = 3e-13, const double tol_pivot = 4.0,
827 const double tol_rank_abs = 3.7e-11, const double tol_rank_rel = 3.7e-11) {
828 Vector<double> w;
829 Matrix<T, Mcompressed_col> L;
830 Matrix<T, Mcompressed_col> trans_U;
831 const size_t rank = LUIFactorization(
832 L, trans_U, Index::null, Index::null, false, w, true, tol_pivot, tol_drop,
833 tol_rank_abs, tol_rank_rel);
834 Q.clear();
835 Q.reserve(w.size() - rank);
836 for (size_t i = 0; i != w.size(); ++i) {
837 if (w[i] <= 0) { Q.push_back(i); }
838 }
839 }
840
841 Matrix& operator*=(const double s) {
842 for (size_t i = 0; i != m.size(); ++i) { m[i] *= s; }
843 return *this;
844 }
845
846 Matrix& operator=(
847 const Matrix<
848 T,
849 MMProd<Minverse_constref<Mcompressed_col_constref>, Mcompressed_col_st_constref>>&
850 m_) {
851 if (m_.scale != T(1) || m_.m2.scale != T(1) || m_.m2.trans) {
853 }
854 if (m_.m1.size1() != m_.m1.size2()) { Exception() << THROW; }
855
856 s1 = m_.m1.m.s1;
857 si.clear();
858 si.push_back(0);
859 index.clear();
860 m.clear();
861 for (size_t k = 0; k != m_.m2.size2(); ++k) {
862 if (m_.m2.si[k + 1] - m_.m2.si[k] > 0) {
863 std::list<std::pair<size_t, T>> tmp;
864 for (size_t j = m_.m2.si[k]; j != m_.m2.si[k + 1]; ++j) {
865 tmp.push_back(std::pair<size_t, T>(m_.m2.index[j], m_.m2.m[j]));
866 }
867 for (typename std::list<std::pair<size_t, T>>::reverse_iterator j = tmp.rbegin();
868 j != tmp.rend(); ++j) {
869 size_t jj_piv_p = m_.m1.m.si[j->first + 1] - 1;
870 if (m_.m1.m.index[jj_piv_p] != j->first) { Exception() << THROW; }
871 T piv = (j->second /= m_.m1.m.m[jj_piv_p]);
872 if (b2000::norm(piv) < 1e-15) { continue; }
873 typename std::list<std::pair<size_t, T>>::iterator jc = tmp.begin();
874 for (size_t jj = m_.m1.m.si[j->first]; jj < jj_piv_p; ++jj) {
875 size_t ii = m_.m1.m.index[jj];
876 T v = -m_.m1.m.m[jj] * piv;
877 while (jc != tmp.end() && jc->first < ii) { ++jc; }
878 if (jc != tmp.end() && jc->first == ii) {
879 jc->second += v;
880 } else {
881 tmp.insert(jc, std::pair<size_t, T>(ii, v));
882 }
883 }
884 }
885 for (typename std::list<std::pair<size_t, T>>::iterator i = tmp.begin();
886 i != tmp.end(); ++i) {
887 if (b2000::norm(i->second) > 1e-15) {
888 index.push_back(i->first);
889 m.push_back(i->second);
890 }
891 }
892 }
893 si.push_back(index.size());
894 }
895 return *this;
896 }
897
898 Matrix& operator=(
899 const Matrix<
900 T,
901 MMProd<Mcompressed_col_st_constref, Minverse_constref<Mcompressed_col_constref>>>&
902 m_) {
903 if (m_.scale != T(1) || m_.m1.scale != T(1) || m_.m1.trans) {
905 }
906 if (m_.m2.size1() != m_.m2.size2()) { Exception() << THROW; }
907
908 s1 = m_.m1.s1;
909 si.clear();
910 si.push_back(0);
911 index.clear();
912 m.clear();
913 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
914 const size_t end_list_flag = m_.m1.size1();
915 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
916 for (size_t k = 0; k != m_.m2.m.size1(); ++k) {
917 size_t end_list = end_list_flag;
918 const size_t* rowind_begin = m_.m1.index + m_.m1.si[k];
919 const size_t* rowind_end = m_.m1.index + m_.m1.si[k + 1];
920 const T* value_begin = m_.m1.m + m_.m1.si[k];
921 while (rowind_begin != rowind_end) {
922 tmp_value[*rowind_begin] = *value_begin++;
923 tmp_index[*rowind_begin] = end_list;
924 end_list = *rowind_begin++;
925 }
926 rowind_begin = m_.m2.m.index + m_.m2.m.si[k];
927 value_begin = m_.m2.m.m + m_.m2.m.si[k];
928 while (*rowind_begin < k) {
929 const size_t* a_rowind_begin = &index[si[*rowind_begin]];
930 const T* a_value_begin = &m[si[*rowind_begin]];
931 const size_t* a_rowind_end = &index[si[*rowind_begin + 1]];
932 ++rowind_begin;
933 while (a_rowind_begin != a_rowind_end) {
934 tmp_value[*a_rowind_begin] -= *a_value_begin++ * *value_begin;
935 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
936 tmp_index[*a_rowind_begin] = end_list;
937 end_list = *a_rowind_begin;
938 }
939 ++a_rowind_begin;
940 }
941 ++value_begin;
942 }
943 T pivot = T(1) / *value_begin;
944 std::vector<std::pair<size_t, T>> res_tmp;
945 while (end_list != end_list_flag) {
946 res_tmp.push_back(std::pair<size_t, T>(end_list, pivot * tmp_value[end_list]));
947 const size_t end_list_next = tmp_index[end_list];
948 tmp_index[end_list] = std::numeric_limits<size_t>::max();
949 tmp_value[end_list] = T(0);
950 end_list = end_list_next;
951 }
952 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
953
954 for (typename std::vector<std::pair<size_t, T>>::iterator i = res_tmp.begin();
955 i != res_tmp.end(); ++i) {
956 index.push_back(i->first);
957 m.push_back(i->second);
958 }
959 si.push_back(m.size());
960 }
961
962 return *this;
963 }
964
965 template <typename T1, typename STORAGE>
966 void scale_row(const Vector<T1, STORAGE>& v) {
967 for (size_t i = 0; i != m.size(); ++i) { m[i] *= v[index[i]]; }
968 }
969
970 template <typename T1, typename STORAGE>
971 void scale_col(const Vector<T1, STORAGE>& v) {
972 if (m.empty()) { return; }
973 for (size_t j = 0; j != size2(); ++j) {
974 T* i = &m[si[j]];
975 T* i_end = &m[si[j + 1]];
976 T1 tmp = v[j];
977 while (i != i_end) { *i++ *= tmp; }
978 }
979 }
980
981 void scale_col_to_norminf(Vector<double, Vdense>& v) {
982 if (m.empty()) { return; }
983 for (size_t j = 0; j != size2(); ++j) {
984 T* i_end = &m[si[j + 1]];
985 T tmp = 0;
986 for (T* i = &m[si[j]]; i != i_end; ++i) {
987 tmp = max_abs(tmp, *i); // std::max(tmp, b2000::norm(*i));
988 }
989 if (tmp == T(0)) { continue; }
990 tmp = T(1) / tmp;
991 v[j] = b2000::real(tmp);
992 for (T* i = &m[si[j]]; i != i_end; ++i) { *i *= tmp; }
993 }
994 }
995
996 template <typename T1>
997 void scale_invert_col(const Vector<T1, Vdense_constref>& v) {
998 if (m.empty()) { return; }
999 T* ii = &m[0];
1000 for (size_t i = 0; i != v.size(); ++i) {
1001 T1 tmp = T1(1) / v[i];
1002 for (T const* i_end = &m[si[i + 1]]; ii != i_end; ++ii) { *ii *= tmp; }
1003 }
1004 }
1005
1006 bool is_null_value() const {
1007 for (size_t i = 0; i != m.size(); ++i) {
1008 if (m[i] != T(0)) { return false; }
1009 }
1010 return true;
1011 }
1012
1013 void remove_zero(const double tol = 0) {
1014 size_t i = si[0];
1015 size_t i_out = i;
1016 for (size_t j = 1; j != si.size(); ++j) {
1017 for (; i != si[j]; ++i) {
1018 if (b2000::norm(m[i]) > tol) {
1019 m[i_out] = m[i];
1020 index[i_out] = index[i];
1021 ++i_out;
1022 }
1023 }
1024 si[j] = i_out;
1025 }
1026 index.resize(i_out);
1027 m.resize(i_out);
1028 }
1029
1030 void row_permute(size_t new_s1, const Index perm) {
1031 if (perm.size() != s1) { Exception() << THROW; }
1032 for (size_t i = 0; i != index.size(); ++i) { index[i] = perm[index[i]]; }
1033 s1 = new_s1;
1034 }
1035
1036 void set_full() {
1037 {
1038 std::vector<T> m_tmp(s1 * size2());
1039 size_t ptri = 0;
1040 size_t ptro = 0;
1041 for (size_t j = 1; j != si.size(); ++j, ptro += s1) {
1042 for (; ptri != si[j]; ++ptri) { m_tmp[ptro + index[ptri]] = m[ptri]; }
1043 }
1044 m.swap(m_tmp);
1045 }
1046 index.resize(m.size());
1047 si[0] = 0;
1048 size_t ptr = 0;
1049 for (size_t j = 1; j != si.size(); ++j) {
1050 si[j] = si[j - 1] + s1;
1051 for (size_t i = 0; i != s1; ++i, ++ptr) { index[ptr] = i; }
1052 }
1053 }
1054
1055 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
1056 l << "column compressed matrix of size (" << m.size1() << ", " << m.size2() << ") ";
1057 l.write(m.si.size(), &m.si[0], 1, "colind");
1058 l.write(m.index.size(), &m.index[0], 1, "rowind");
1059 l.write(m.m.size(), &m.m[0], 1, "value");
1060 return l;
1061 }
1062
1063 friend std::ostream& operator<<(std::ostream& out, const Matrix& m) {
1064 /*
1065 size_t i = m.si[0];
1066 for (size_t j = 0; j != m.si.size() - 1; ++j)
1067 for (size_t i_end = m.si[j + 1]; i != i_end; ++i)
1068 out << "(" << m.index[i] << ", " << j << ") = " << m.m[i] << std::endl;
1069
1070 */
1071 std::vector<size_t> sii(m.si);
1072 const size_t s2 = sii.size() - 1;
1073 out << "(";
1074 for (size_t i = 0;;) {
1075 out << "(";
1076 for (size_t j = 0;;) {
1077 if (sii[j] == m.si[j + 1] || m.index[sii[j]] != i) {
1078 out << "0.0";
1079 } else {
1080 out << m.m[sii[j]++];
1081 }
1082 if (++j != s2) {
1083 out << ", ";
1084 } else {
1085 break;
1086 }
1087 }
1088 out << ")";
1089 if (++i != m.s1) {
1090 out << "," << std::endl;
1091 } else {
1092 break;
1093 }
1094 }
1095 out << ")";
1096 return out;
1097 }
1098
1099 static Matrix null;
1100
1101private:
1102 size_t s1;
1103 std::vector<size_t> si;
1104 std::vector<T> m;
1105 std::vector<size_t> index;
1106 MVFRIEND;
1107};
1108
1109template <typename T>
1110Matrix<T, Mcompressed_col> Matrix<T, Mcompressed_col>::null;
1111
1112// Right looking LU factorisation
1113
1114// The output L is triangular inferior unit matrix. The output
1115// trans_L is triangular inferior matrix without zero on the diagonal.
1116// At output, L.size2() = trans_U.size2() = rank of the input matrix.
1117template <typename T>
1118size_t Matrix<T, Mcompressed_col>::LUIFactorization(
1119 Matrix<T, Mcompressed_col>& L, Matrix<T, Mcompressed_col>& trans_U, Index& P, Index& Q,
1120 const bool compute_LU, Vector<double>& w, const bool rook_pivot, double tol_pivot,
1121 const double drop_tol, const double tol_rank_abs, const double tol_rank_rel,
1122 const Index& col_to_remove) {
1123 if (tol_pivot < 0) { tol_pivot = rook_pivot ? 4.0 : 10.0; }
1124
1125 const size_t s2 = size2();
1126 const size_t min_mn = std::min(s1, s2);
1127
1128 std::set<size_t> empty_row;
1129 std::set<size_t> empty_col;
1130 size_t* P_empty_row = 0;
1131 size_t* Q_empty_col = 0;
1132 if (compute_LU) {
1133 P.resize(s1);
1134 P_empty_row = &P.back();
1135 Q.resize(s2);
1136 Q_empty_col = &Q.back();
1137 }
1138
1139 L.s1 = s1;
1140 L.si.clear();
1141 L.si.push_back(0);
1142 L.index.clear();
1143 L.m.clear();
1144
1145 trans_U.s1 = s2;
1146 trans_U.si.clear();
1147 trans_U.si.push_back(0);
1148 trans_U.index.clear();
1149 trans_U.m.clear();
1150
1151 Vector<double> U_diag;
1152 if (!w.is_null()) {
1153 U_diag.resize(s2);
1154 U_diag.set_zero();
1155 w.resize(s2);
1156 w.set_zero();
1157 }
1158
1159 std::vector<std::map<size_t, T>> col(s2);
1160 std::vector<std::map<size_t, T*>> row(s1);
1161 std::vector<double> col_max(s2);
1162 std::vector<double> row_max(s1);
1163 {
1164 const size_t* col_to_remove_ptr = 0;
1165 const size_t* col_to_remove_ptr_end = 0;
1166 if (!col_to_remove.is_null() && !col_to_remove.empty()) {
1167 col_to_remove_ptr = &col_to_remove[0];
1168 col_to_remove_ptr_end = &col_to_remove.back() + 1;
1169 }
1170 size_t i = si[0];
1171 for (size_t j = 0; j != s2; ++j) {
1172 if (col_to_remove_ptr && col_to_remove_ptr != col_to_remove_ptr_end
1173 && j == *col_to_remove_ptr) {
1174 ++col_to_remove_ptr;
1175 i = si[j + 1];
1176 continue;
1177 }
1178 const size_t i_end = si[j + 1];
1179 for (; i != i_end; ++i) {
1180 const size_t ii = index[i];
1181 const double nm = b2000::norm(m[i]);
1182 if (nm > drop_tol) {
1183 T* ptr;
1184 {
1185 typename std::map<size_t, T>& col_j = col[j];
1186 ptr = &(col_j.insert(col_j.end(), std::pair<size_t, T>(ii, m[i]))->second);
1187 }
1188 {
1189 typename std::map<size_t, T*>& row_i = row[ii];
1190 row_i.insert(row_i.end(), std::pair<size_t, T*>(j, ptr));
1191 }
1192 if (nm > col_max[j]) { col_max[j] = nm; }
1193 if (nm > row_max[ii]) { row_max[ii] = nm; }
1194 }
1195 }
1196 }
1197 }
1198
1199 // initialise the row/com degree map
1200 using degree_t = std::multimap<size_t, size_t>;
1201 using degree_iter_t = std::vector<degree_t::iterator>;
1202
1203 degree_t col_degree;
1204 degree_iter_t col_degree_iter(s2);
1205 degree_t row_degree;
1206 degree_iter_t row_degree_iter(s1);
1207 for (size_t i = 0; i != s2; ++i) {
1208 if (!col[i].empty()) {
1209 col_degree_iter[i] = col_degree.insert(std::pair<size_t, size_t>(col[i].size(), i));
1210 } else {
1211 if (Q_empty_col) { *Q_empty_col-- = i; }
1212 empty_col.insert(i);
1213 }
1214 }
1215 for (size_t i = 0; i != s1; ++i) {
1216 if (!row[i].empty()) {
1217 row_degree_iter[i] = row_degree.insert(std::pair<size_t, size_t>(row[i].size(), i));
1218 } else {
1219 if (P_empty_row) { *P_empty_row-- = i; }
1220 empty_row.insert(i);
1221 }
1222 }
1223
1224 // iteration on the LU decomposition
1225 size_t k;
1226 for (k = 0; k != min_mn; ++k) {
1227 size_t i_pivot = s1;
1228 size_t j_pivot = s2;
1229
1230 // chose a pivot using the Markowitz strategy to reduce the
1231 // fill-in and the threshold partial pivoting or the threshold
1232 // rook pivoting strategy to stabilise the LU factorisation.
1233 {
1234 degree_t::const_iterator j = col_degree.begin();
1235 degree_t::const_iterator i = row_degree.begin();
1236 if (j == col_degree.end() || i == row_degree.end()) { break; }
1237 assert(col[j->second].size() == j->first);
1238 assert(row[i->second].size() == i->first);
1239 double min_tol = std::numeric_limits<double>::max();
1240 double min_degree = s1 * s2;
1241 const size_t min_degree_all = i->first * j->first;
1242 for (;;) {
1243 const size_t min_degree_all1 = i->first * j->first;
1244 if (j->first <= i->first) {
1245 typename std::map<size_t, T>::const_iterator i1 = col[j->second].begin();
1246 if (j->first == 1 && row_degree_iter[i1->first] != row_degree.end()
1247 && col_degree_iter[j->second] != col_degree.end()) {
1248 // The order we take it does not influence the
1249 // fill-in nor the numerical stability of the
1250 // factorization.
1251 i_pivot = i1->first;
1252 j_pivot = j->second;
1253 assert(col[j_pivot].find(i_pivot) != col[j_pivot].end());
1254 break;
1255 }
1256 const typename std::map<size_t, T>::const_iterator i1_end =
1257 col[j->second].end();
1258 for (; i1 != i1_end; ++i1) {
1259 const size_t d = j->first * row[i1->first].size();
1260 if (d <= min_degree) {
1261 const T iv = T(1) / i1->second;
1262 double vc = b2000::norm(col_max[j->second] * iv);
1263 if (rook_pivot) {
1264 vc = std::max(vc, double(b2000::norm(row_max[i1->first] * iv)));
1265 }
1266 if (vc < min_tol && vc < tol_pivot
1267 && row_degree_iter[i1->first] != row_degree.end()
1268 && col_degree_iter[j->second] != col_degree.end()) {
1269 min_tol = vc;
1270 min_degree = d;
1271 i_pivot = i1->first;
1272 j_pivot = j->second;
1273 assert(col[j_pivot].find(i_pivot) != col[j_pivot].end());
1274 }
1275 }
1276 }
1277 ++j;
1278 } else {
1279 typename std::map<size_t, T*>::const_iterator j1 = row[i->second].begin();
1280 if (i->first == 1 && row_degree_iter[i->second] != row_degree.end()
1281 && col_degree_iter[j1->first] != col_degree.end()) {
1282 // The order we take it does not influence the
1283 // fill-in nor the numerical stability of the
1284 // factorization.
1285 i_pivot = i->second;
1286 j_pivot = j1->first;
1287 assert(col[j_pivot].find(i_pivot) != col[j_pivot].end());
1288 break;
1289 }
1290 const typename std::map<size_t, T*>::const_iterator j1_end =
1291 row[i->second].end();
1292 for (; j1 != j1_end; ++j1) {
1293 const size_t d = i->first * col[j1->first].size();
1294 if (d <= min_degree) {
1295 const T iv = T(1) / *(j1->second);
1296 double vc = b2000::norm(col_max[j1->first] * iv);
1297 if (rook_pivot) {
1298 vc = std::min(vc, double(b2000::norm(row_max[i->second] * iv)));
1299 }
1300 if (vc < min_tol && vc < tol_pivot
1301 && row_degree_iter[i->second] != row_degree.end()
1302 && col_degree_iter[j1->first] != col_degree.end()) {
1303 min_tol = vc;
1304 min_degree = d;
1305 i_pivot = i->second;
1306 j_pivot = j1->first;
1307 assert(col[j_pivot].find(i_pivot) != col[j_pivot].end());
1308 }
1309 }
1310 }
1311 ++i;
1312 }
1313 if (min_tol < 1.0001 && min_degree == min_degree_all) { break; }
1314 if (min_tol < tol_pivot && min_degree_all1 > min_degree_all) { break; }
1315 if (j == col_degree.end() || i == row_degree.end()) { break; }
1316 }
1317 }
1318
1319 if (i_pivot == s1) { Exception() << THROW; }
1320
1321 col_degree.erase(col_degree_iter[j_pivot]);
1322 col_degree_iter[j_pivot] = col_degree.end();
1323 row_degree.erase(row_degree_iter[i_pivot]);
1324 row_degree_iter[i_pivot] = row_degree.end();
1325 if (compute_LU) {
1326 P[k] = i_pivot;
1327 Q[k] = j_pivot;
1328 }
1329
1330 typename std::map<size_t, T>::iterator i = col[j_pivot].find(i_pivot);
1331 assert(i != col[j_pivot].end());
1332 T value_pivot = i->second;
1333
1334 // computation of the pivot column
1335 {
1336 const T inv_value_pivot = T(1) / value_pivot;
1337 i = col[j_pivot].begin();
1338 const typename std::map<size_t, T>::const_iterator i_end = col[j_pivot].end();
1339 for (; i != i_end; ++i) {
1340 L.index.push_back(i->first);
1341 L.m.push_back(i->first == i_pivot ? T(1) : i->second * inv_value_pivot);
1342 row[i->first].erase(j_pivot);
1343 }
1344 }
1345 col[j_pivot].clear();
1346
1347 // update the sub matrix
1348 trans_U.index.push_back(j_pivot);
1349 trans_U.m.push_back(value_pivot);
1350 {
1351 typename std::map<size_t, T*>::const_iterator j = row[i_pivot].begin();
1352 const typename std::map<size_t, T*>::const_iterator j_end = row[i_pivot].end();
1353 for (; j != j_end; ++j) {
1354 typename std::map<size_t, T>& col_j = col[j->first];
1355 typename std::map<size_t, T>::iterator ii = col_j.find(i_pivot);
1356 assert(ii != col_j.end());
1357 trans_U.index.push_back(j->first);
1358 trans_U.m.push_back(ii->second);
1359 col_j.erase(ii);
1360 for (size_t iii = L.si.back(); iii != L.index.size(); ++iii) {
1361 if (L.index[iii] != i_pivot) {
1362 const T v = -L.m[iii] * trans_U.m.back();
1363 ii = col_j.find(L.index[iii]);
1364 if (ii == col_j.end()) {
1365 T* ptr = &(col_j.insert(std::pair<size_t, T>(L.index[iii], v))
1366 .first->second);
1367 row[L.index[iii]].insert(std::pair<size_t, T*>(j->first, ptr));
1368 } else {
1369 ii->second += v;
1370 if (b2000::norm(ii->second) <= drop_tol) {
1371 col_j.erase(ii);
1372 row[L.index[iii]].erase(j->first);
1373 }
1374 }
1375 }
1376 }
1377 }
1378 }
1379 row[i_pivot].clear();
1380
1381 // Update col degree map and maximum values.
1382 for (size_t jj = trans_U.si.back(); jj != trans_U.index.size(); ++jj) {
1383 const size_t j = trans_U.index[jj];
1384 if (j == j_pivot) { continue; }
1385 {
1386 typename std::map<size_t, T>::const_iterator i = col[j].begin();
1387 const typename std::map<size_t, T>::const_iterator i_end = col[j].end();
1388 double max = 0;
1389 for (; i != i_end; ++i) { max = std::max(max, double(b2000::norm(i->second))); }
1390 col_max[j] = max;
1391 }
1392 if (col_degree_iter[j] != col_degree.end()) { col_degree.erase(col_degree_iter[j]); }
1393 col_degree_iter[j] = col_degree.end();
1394 if (!col[j].empty()) {
1395 col_degree_iter[j] = col_degree.insert(std::pair<size_t, size_t>(col[j].size(), j));
1396 } else {
1397 if (Q_empty_col && empty_col.find(j) == empty_col.end()) { *Q_empty_col-- = j; }
1398 empty_col.insert(j);
1399 }
1400 }
1401
1402 // Update row degree map and maximum values.
1403 for (size_t ii = L.si.back(); ii != L.index.size(); ++ii) {
1404 const size_t i = L.index[ii];
1405 if (i == i_pivot) { continue; }
1406 {
1407 typename std::map<size_t, T*>::const_iterator j = row[i].begin();
1408 const typename std::map<size_t, T*>::const_iterator j_end = row[i].end();
1409 double max = 0;
1410 for (; j != j_end; ++j) { max = std::max(max, double(b2000::norm(*(j->second)))); }
1411 row_max[i] = max;
1412 }
1413 if (row_degree_iter[i] != row_degree.end()) { row_degree.erase(row_degree_iter[i]); }
1414 row_degree_iter[i] = row_degree.end();
1415 if (!row[i].empty()) {
1416 row_degree_iter[i] = row_degree.insert(std::pair<size_t, size_t>(row[i].size(), i));
1417 } else {
1418 if (P_empty_row && empty_row.find(i) == empty_row.end()) { *P_empty_row-- = i; }
1419 empty_row.insert(i);
1420 }
1421 }
1422
1423 // update w
1424 if (!w.is_null()) {
1425 U_diag[j_pivot] = b2000::norm(value_pivot);
1426 for (size_t jj = trans_U.si.back(); jj != trans_U.index.size(); ++jj) {
1427 const size_t j = trans_U.index[jj];
1428 w[j] = std::max(w[j], double(b2000::norm(trans_U.m[jj])));
1429 }
1430 }
1431
1432 if (compute_LU) {
1433 L.si.push_back(L.index.size());
1434 trans_U.si.push_back(trans_U.index.size());
1435 } else {
1436 L.index.clear();
1437 L.m.clear();
1438 trans_U.index.clear();
1439 trans_U.m.clear();
1440 }
1441 }
1442
1443 if (compute_LU) {
1444 {
1445 size_t kk = k;
1446 for (degree_t::const_iterator i = row_degree.begin(); i != row_degree.end();
1447 ++i, ++kk) {
1448 P[kk] = i->second;
1449 }
1450 std::sort(P.begin() + k, P.end());
1451 }
1452
1453 using p_iter =
1454 pair_iterator<std::vector<size_t>::iterator, typename std::vector<T>::iterator>;
1455 {
1456 Index inv_P = P.make_dual();
1457 size_t i = L.si[0];
1458 for (Index::const_iterator j = L.si.begin() + 1; j != L.si.end(); ++j) {
1459 const size_t i_end = *j;
1460 p_iter ii_begin(L.index.begin() + i, L.m.begin() + i);
1461 for (; i != i_end; ++i) {
1462 size_t& ii = L.index[i];
1463 ii = inv_P[ii];
1464 }
1465 p_iter ii_end(L.index.begin() + i, L.m.begin() + i);
1466 std::sort(ii_begin, ii_end, CompareFirstOfPair());
1467 }
1468 }
1469
1470 {
1471 size_t kk = k;
1472 for (degree_t::const_iterator j = col_degree.begin(); j != col_degree.end();
1473 ++j, ++kk) {
1474 Q[kk] = j->second;
1475 }
1476 std::sort(Q.begin() + k, Q.end());
1477 }
1478 {
1479 Index inv_Q = Q.make_dual();
1480 size_t i = trans_U.si[0];
1481 for (Index::const_iterator j = trans_U.si.begin() + 1; j != trans_U.si.end(); ++j) {
1482 const size_t i_end = *j;
1483 p_iter ii_begin(trans_U.index.begin() + i, trans_U.m.begin() + i);
1484 for (; i != i_end; ++i) {
1485 size_t& ii = trans_U.index[i];
1486 ii = inv_Q[ii];
1487 }
1488 p_iter ii_end(trans_U.index.begin() + i, trans_U.m.begin() + i);
1489 std::sort(ii_begin, ii_end, CompareFirstOfPair());
1490 }
1491 }
1492 }
1493
1494 // set w[j] <= 0 if dependent column detected
1495 size_t rank = s2;
1496 if (!w.is_null()) {
1497 for (size_t j = 0; j != s2; ++j) {
1498 if (U_diag[j] < tol_rank_abs || U_diag[j] < tol_rank_rel * w[j]) {
1499 w[j] *= -1;
1500 --rank;
1501 }
1502 }
1503 }
1504 return rank;
1505}
1506
1507struct Mcompressed_col_ref {
1508 using base = Mcompressed_col_ref;
1509 using const_base = Mcompressed_col_st_constref;
1510 using copy = Mcompressed_col;
1511};
1512
1513template <typename T>
1514class Matrix<T, Mcompressed_col_ref> {
1515public:
1516 Matrix() : s1(0), s2(0), si(0), index(0), m(0) {}
1517
1518 Matrix(size_t s1_, size_t s2_, size_t snn_, size_t* si_, size_t* index_, T* m_)
1519 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_) {}
1520
1521 Matrix(const Matrix& m_) : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
1522
1523 Matrix(Matrix<T, Mcompressed_col>& m_)
1524 : s1(m_.s1), s2(m_.si.size() - 1), si(&m_.si[0]), index(&m_.index[0]), m(&m_.m[0]) {}
1525
1526 bool is_null() const { return m == 0; }
1527
1528 bool is_null_value() const {
1529 for (size_t i = si[0]; i != si[s2]; ++i) {
1530 if (m[i] != 0) { return false; }
1531 }
1532 return true;
1533 }
1534
1535 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(s1, s2); }
1536
1537 size_t size1() const { return s1; }
1538
1539 size_t size2() const { return s2; }
1540
1541 T operator()(size_t i, size_t j) const {
1542 const size_t* s = index + si[j];
1543 const size_t* e = index + si[j + 1];
1544 const size_t* ii = std::lower_bound(s, e, i);
1545 if (ii < e && *ii == i) { return m[ii - index]; }
1546 return 0;
1547 }
1548
1549 template <typename T1>
1550 void scale_row(const Vector<T1, Vdense_constref>& v) {
1551 for (size_t i = si[0]; i != si[s2]; ++i) { m[i] *= v[index[i]]; }
1552 }
1553
1554 template <typename T1>
1555 void scale_col(const Vector<T1, Vdense_constref>& v) {
1556 if (si[s2] == 0) { return; }
1557 for (size_t j = 0; j != size2(); ++j) {
1558 T* i = m + si[j];
1559 T* i_end = m + si[j + 1];
1560 T1 tmp = v[j];
1561 while (i != i_end) { *i *= tmp; }
1562 }
1563 }
1564
1565 template <typename T1>
1566 void scale_invert_col(const Vector<T1, Vdense_constref>& v) {
1567 if (si[s2] == 0) { return; }
1568 T* ii = m;
1569 for (size_t i = 0; i != v.size(); ++i) {
1570 T1 tmp = T1(1) / v[i];
1571 for (T const* i_end = m + index[i + 1]; ii != i_end; ++ii) { *ii *= tmp; }
1572 }
1573 }
1574
1575 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
1576 l << "column compressed matrix of size (" << m.size1() << ", " << m.size2() << ") ";
1577 l.write(m.s2 + 1, m.si, 1, "colind");
1578 l.write(m.si[m.s2], m.index + m.si[0], 1, "rowind");
1579 l.write(m.si[m.s2], m.m + m.si[0], 1, "value");
1580 return l;
1581 }
1582
1583 friend std::ostream& operator<<(std::ostream& out, const Matrix& m) {
1584 size_t i = m.si[0];
1585 for (size_t j = 0; j != m.s2; ++j) {
1586 for (size_t i_end = m.si[j + 1]; i != i_end; ++i) {
1587 out << "(" << m.index[i] << ", " << j << ") = " << m.m[i] << std::endl;
1588 }
1589 }
1590 return out;
1591 }
1592
1593 static Matrix null;
1594
1595private:
1596 size_t s1;
1597 size_t s2;
1598 size_t* si;
1599 size_t* index;
1600 T* m;
1601 MVFRIEND;
1602};
1603
1604template <typename T>
1605Matrix<T, Mcompressed_col_ref> Matrix<T, Mcompressed_col_ref>::null;
1606
1607struct Mcompressed_col_constref {
1608 using base = Mcompressed_col_st_constref;
1609 using const_base = Mcompressed_col_st_constref;
1610 using copy = Mcompressed_col;
1611};
1612
1613template <typename T>
1614class Matrix<T, Mcompressed_col_constref> {
1615public:
1616 Matrix() : s1(0), s2(0), si(0), index(0), m(0) {}
1617
1618 Matrix(
1619 size_t s1_, size_t s2_, size_t snn_, const size_t* si_, const size_t* index_, const T* m_)
1620 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_) {}
1621
1622 Matrix(const Matrix& m_) : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
1623
1624 Matrix(const Matrix<T, Mcompressed_col_ref>& m_)
1625 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m) {}
1626
1627 Matrix(const Matrix<T, Mcompressed_col>& m_)
1628 : s1(m_.s1), s2(m_.si.size() - 1), si(&m_.si[0]), index(&m_.index[0]), m(&m_.m[0]) {}
1629
1630 bool is_null() const { return m == 0; }
1631
1632 bool is_null_value() const {
1633 for (size_t i = si[0]; i != si[s2]; ++i) {
1634 if (m[i] != T(0)) { return false; }
1635 }
1636 return true;
1637 }
1638
1639 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(s1, s2); }
1640
1641 size_t size1() const { return s1; }
1642
1643 size_t size2() const { return s2; }
1644
1645 T operator()(size_t i, size_t j) const {
1646 const size_t* s = index + si[j];
1647 const size_t* e = index + si[j + 1];
1648 const size_t* ii = std::lower_bound(s, e, i);
1649 if (ii < e && *ii == i) { return m[ii - index]; }
1650 return 0;
1651 }
1652
1653 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
1654 l << "column compressed matrix of size (" << m.size1() << ", " << m.size2() << ") ";
1655 l.write(m.s2 + 1, m.si, 1, "colind");
1656 l.write(m.si[m.s2], m.index + m.si[0], 1, "rowind");
1657 l.write(m.si[m.s2], m.m + m.si[0], 1, "value");
1658 return l;
1659 }
1660
1661 friend std::ostream& operator<<(std::ostream& out, const Matrix& m) {
1662 size_t i = m.si[0];
1663 for (size_t j = 0; j != m.s2; ++j) {
1664 for (size_t i_end = m.si[j + 1]; i != i_end; ++i) {
1665 out << "(" << m.index[i] << ", " << j << ") = " << m.m[i] << std::endl;
1666 }
1667 }
1668 return out;
1669 }
1670
1674 void LUFactorization(
1675 Matrix<T, Mcompressed_col>& trans_L, Matrix<T, Mcompressed_col>& U, Index& P, Index& Q,
1676 Vector<double, Vdense>& R);
1677
1678 static Matrix null;
1679
1680private:
1681 static void UMFPACK_clean_incomplete_factorization(
1682 Matrix<T, Mcompressed_col>& trans_L, Matrix<T, Mcompressed_col>& U, const size_t nb_udiag,
1683 Index& P, Index& Q, Vector<double, Vdense>& R);
1684
1685 size_t s1;
1686 size_t s2;
1687 const size_t* si;
1688 const size_t* index;
1689 const T* m;
1690 MVFRIEND;
1691};
1692
1693template <>
1694void Matrix<double, Mcompressed_col_constref>::LUFactorization(
1695 Matrix<double, Mcompressed_col>& trans_L, Matrix<double, Mcompressed_col>& U, Index& P,
1696 Index& Q, Vector<double, Vdense>& R);
1697
1698template <>
1699void Matrix<b2000::csda<double>, Mcompressed_col_constref>::LUFactorization(
1700 Matrix<b2000::csda<double>, Mcompressed_col>& trans_L,
1701 Matrix<b2000::csda<double>, Mcompressed_col>& U, Index& P, Index& Q,
1702 Vector<double, Vdense>& R);
1703
1704template <>
1705void Matrix<std::complex<double>, Mcompressed_col_constref>::LUFactorization(
1706 Matrix<std::complex<double>, Mcompressed_col>& trans_L,
1707 Matrix<std::complex<double>, Mcompressed_col>& U, Index& P, Index& Q,
1708 Vector<double, Vdense>& R);
1709
1710template <typename T>
1711Matrix<T, Mcompressed_col_constref> Matrix<T, Mcompressed_col_constref>::null;
1712
1713struct Mcompressed_col_st_constref {
1714 using base = Mcompressed_col_st_constref;
1715 using const_base = Mcompressed_col_st_constref;
1716 using copy = Mcompressed_col;
1717};
1718
1719template <typename T>
1720class Matrix<T, Mcompressed_col_st_constref> {
1721public:
1722 Matrix() : s1(0), s2(0), si(0), index(0), m(0), scale(0), trans(0) {}
1723
1724 Matrix(
1725 size_t s1_, size_t s2_, size_t snn_, const size_t* si_, const size_t* index_, const T* m_,
1726 T scale_, bool trans_)
1727 : s1(s1_), s2(s2_), si(si_), index(index_), m(m_), scale(scale_), trans(trans_) {}
1728
1729 Matrix(const Matrix& m_)
1730 : s1(m_.s1),
1731 s2(m_.s2),
1732 si(m_.si),
1733 index(m_.index),
1734 m(m_.m),
1735 scale(m_.scale),
1736 trans(m_.trans) {}
1737
1738 Matrix(const Matrix<T, Mcompressed_col_ref>& m_)
1739 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m), scale(1), trans(false) {}
1740
1741 Matrix(const Matrix<T, Mcompressed_col_constref>& m_)
1742 : s1(m_.s1), s2(m_.s2), si(m_.si), index(m_.index), m(m_.m), scale(1), trans(false) {}
1743
1744 Matrix(const Matrix<T, Mcompressed_col>& m_)
1745 : s1(m_.s1),
1746 s2(m_.si.size() - 1),
1747 si(&m_.si[0]),
1748 index(&m_.index[0]),
1749 m(&m_.m[0]),
1750 scale(1),
1751 trans(false) {}
1752
1753 bool is_null() const { return m == 0; }
1754
1755 std::pair<size_t, size_t> size() const {
1756 if (trans) {
1757 return std::pair<size_t, size_t>(s2, s1);
1758 } else {
1759 return std::pair<size_t, size_t>(s1, s2);
1760 }
1761 }
1762
1763 size_t size1() const {
1764 if (trans) {
1765 return s2;
1766 } else {
1767 return s1;
1768 }
1769 }
1770
1771 size_t size2() const {
1772 if (trans) {
1773 return s1;
1774 } else {
1775 return s2;
1776 }
1777 }
1778
1779 T operator()(size_t i, size_t j) const {
1780 if (trans) { std::swap(i, j); }
1781 const size_t* s = index + si[j];
1782 const size_t* e = index + si[j + 1];
1783 const size_t* ii = std::lower_bound(s, e, i);
1784 if (ii < e && *ii == i) { return scale * m[ii - index]; }
1785 return 0;
1786 }
1787
1788 Matrix& operator*(T scale_) {
1789 scale *= scale_;
1790 return *this;
1791 }
1792
1793 Matrix& transpose() {
1794 trans = trans ? false : true;
1795 return *this;
1796 }
1797
1798 static Matrix null;
1799
1800private:
1801 bool operator==(const Matrix& m_) const {
1802 return s1 == m_.s1 && s2 == m_.s2 && si == m_.si && index == m_.index && m == m_.m
1803 && scale == m_.scale && trans == m_.trans;
1804 }
1805
1806 size_t s1;
1807 size_t s2;
1808 const size_t* si;
1809 const size_t* index;
1810 const T* m;
1811 T scale;
1812 char trans;
1813 MVFRIEND;
1814};
1815
1816template <typename T>
1817Matrix<T, Mcompressed_col_st_constref> Matrix<T, Mcompressed_col_st_constref>::null;
1818
1819struct Mcompressed_col_update_inv {
1820 using base = Mcompressed_col_ref;
1821 using const_base = Mcompressed_col_st_constref;
1822 using copy = Mcompressed_col_update_inv;
1823 using inverse = Mcompressed_col_update_inv;
1824};
1825
1826template <typename T>
1827class Matrix<T, Mcompressed_col_update_inv> {
1828public:
1829 Matrix(
1830 size_t s1_ = 0,
1831 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
1832 const Dictionary& dictionary_ = Dictionary::get_empty())
1833 : s1(s1_), value(s1_), solver(0), connectivity(connectivity_), dictionary(&dictionary_) {}
1834
1835 Matrix(const Matrix& m_)
1836 : s1(m_.s1),
1837 si(m_.si),
1838 m(m_.m),
1839 index(m_.index),
1840 value(m_.value),
1841 solver(0),
1842 connectivity(m_.connectivity),
1843 dictionary(m_.dictionary) {}
1844
1845 virtual ~Matrix() { delete solver; }
1846
1847 void resize(
1848 size_t s, SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
1849 const Dictionary& dictionary_ = Dictionary::get_empty()) {
1850 if (si.empty()) {
1851 value.resize(s);
1852 s1 = s;
1853 } else {
1855 }
1856 if (connectivity_ != sparse_matrix_connectivity_unknown) { connectivity = connectivity_; }
1857 if (&dictionary_ != &Dictionary::get_empty()) { dictionary = &dictionary_; }
1858 }
1859
1860 void resize(
1861 size_t s1_, size_t s2,
1862 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
1863 const Dictionary& dictionary_ = Dictionary::get_empty()) {
1864 s1 = s1_;
1865 if (si.empty()) {
1866 value.resize(s2);
1867 } else {
1869 }
1870 if (connectivity_ != sparse_matrix_connectivity_unknown) { connectivity = connectivity_; }
1871 if (&dictionary_ != &Dictionary::get_empty()) { dictionary = &dictionary_; }
1872 }
1873
1874 void set_same_structure(const Matrix& m_) {
1875 s1 = m_.s1;
1876 si = m_.si;
1877 index = m_.index;
1878 m.resize(m_.m.size());
1879 std::fill(m.begin(), m.end(), 0);
1880 connectivity = m_.connectivity;
1881 dictionary = m_.dictionary;
1882 }
1883
1884 virtual void set_zero() {
1885 std::fill(si.begin(), si.end(), 0);
1886 index.resize(0);
1887 m.resize(0);
1888 delete solver;
1889 solver = 0;
1890 }
1891
1892 virtual bool is_null() const { return this == &null; }
1893
1894 virtual void set_zero_same_struct() {
1895 for (typename std::vector<std::vector<std::pair<size_t, T>>>::iterator i = value.begin();
1896 i != value.end(); ++i) {
1897 i->clear();
1898 }
1899 std::fill(m.begin(), m.end(), 0);
1900 if (solver) { solver->update_value(); }
1901 }
1902
1903 std::pair<size_t, size_t> size() const {
1904 size_t s;
1905 if (si.empty()) {
1906 s = value.size();
1907 } else {
1908 s = si.size() - 1;
1909 }
1910 return std::pair<size_t, size_t>(s1, s);
1911 }
1912
1913 size_t size1() const { return s1; }
1914
1915 size_t size2() const {
1916 if (si.empty()) { return value.size(); }
1917 return si.size() - 1;
1918 }
1919
1926 void InitializeRow(size_t row, const std::map<size_t, T>& row_contributions) {
1927 value[row].reserve(row_contributions.size());
1928 auto pos{begin(row_contributions)};
1929
1930 for (; pos != end(row_contributions); pos++) {
1931 value[row].push_back(std::make_pair(pos->first, pos->second));
1932 }
1933 }
1934
1935 size_t get_nb_nonzero() const {
1936 if (si.empty()) {
1937 size_t r = 0;
1938 for (size_t i = 0; i != value.size(); ++i) { r += value[i].size(); }
1939 }
1940 return index.size();
1941 }
1942
1949 T operator()(size_t i, size_t j) const {
1950 if (si.empty()) {
1951 typename std::vector<std::pair<size_t, T>>::const_iterator ii = std::lower_bound(
1952 value[j].begin(), value[j].end(), std::pair<size_t, T>(i, 0),
1953 CompareFirstOfPair());
1954
1955 if (ii != value[j].end() && ii->first == i) { return ii->second; }
1956 } else {
1957 std::vector<size_t>::const_iterator s = index.begin() + si[j];
1958 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
1959 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
1960 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
1961 }
1962 return 0;
1963 }
1964
1971 T& operator()(size_t i, size_t j) {
1972 if (si.empty()) {
1975 typename std::vector<std::pair<size_t, T>>::iterator ii = std::lower_bound(
1976 value[j].begin(), value[j].end(), std::pair<size_t, T>(i, 0),
1977 CompareFirstOfPair());
1978
1979 if (ii != value[j].end() && ii->first == i) { return ii->second; }
1980 } else {
1981 std::vector<size_t>::const_iterator s = index.begin() + si[j];
1982 std::vector<size_t>::const_iterator e = index.begin() + si[j + 1];
1983 std::vector<size_t>::const_iterator ii = std::lower_bound(s, e, i);
1984 if (ii < e && *ii == i) { return m[ii - index.begin()]; }
1985 }
1986 static T zero = 0;
1987 return zero;
1988 }
1989
1990 Matrix& operator+=(
1991 const Matrix<T, Mstructured_constref<Mrectangle_increment_st_constref>>& m_) {
1992 if (size() != m_.size()) {
1993 Exception() << "The two matrix do not have the same size, " << size() << " and "
1994 << m_.size() << THROW;
1995 }
1996 for (size_t j = 0; j != m_.m.s2; ++j) {
1997 std::vector<std::pair<size_t, T>> tmp;
1998 tmp.reserve(m_.m.s1);
1999 for (size_t i = 0; i != m_.m.s1; ++i) {
2000 tmp.push_back(std::pair<size_t, T>(m_.index[i], m_.m(i, j)));
2001 }
2002 std::sort(tmp.begin(), tmp.end(), CompareFirstOfPair());
2003 if (m_.index2) {
2004 add_colomn(m_.index2[j], tmp.begin(), tmp.end());
2005 } else {
2006 add_colomn(m_.index[j], tmp.begin(), tmp.end());
2007 }
2008 }
2009 return *this;
2010 }
2011
2012 Matrix& operator+=(const Matrix<
2013 T, MMProd<
2014 MMProd<
2015 Mcompressed_col_st_constref,
2016 Mstructured_constref<Mrectangle_increment_st_constref>>,
2017 Mcompressed_col_st_constref>>& m_) {
2018 if (size1() < m_.size1() || size2() < m_.size2()) {
2019 Exception() << "The two matrix do not have the same size, " << size() << " and "
2020 << m_.size() << THROW;
2021 }
2022 if (m_.m1.m1.trans == true || m_.m1.m2.m.s1 != m_.m1.m2.m.s2 || m_.m2.trans == false
2023 || m_.m1.m1.si != m_.m2.si || m_.m1.m1.index != m_.m2.index || m_.m1.m1.m != m_.m2.m) {
2025 }
2026
2027 const size_t* colind = m_.m2.si;
2028 const size_t* rowind = m_.m2.index;
2029 const T* value_ = m_.m2.m;
2030 const size_t input_size = m_.m1.m2.m.s1;
2031 const size_t* input_dof_numbering = m_.m1.m2.index;
2032
2033 bool new_output_matrix = false;
2034 std::map<size_t, size_t> tmp_rowind;
2035 const size_t* input_dof_numbering_begin = input_dof_numbering;
2036 const size_t* const input_dof_numbering_end = input_dof_numbering_begin + input_size;
2037 while (input_dof_numbering_begin != input_dof_numbering_end) {
2038 const size_t* rowind_begin = rowind + colind[*input_dof_numbering_begin];
2039 const size_t* const rowind_end = rowind + colind[*input_dof_numbering_begin + 1];
2040 const T* value_begin = value_ + colind[*input_dof_numbering_begin];
2041 std::pair<size_t, size_t> tmp_rowind_insert(
2042 0, input_dof_numbering_begin - input_dof_numbering);
2043 while (rowind_begin != rowind_end) {
2044 tmp_rowind_insert.first = *rowind_begin;
2045 if (!tmp_rowind.insert(tmp_rowind_insert).second || *value_begin != T(1)) {
2046 new_output_matrix = true;
2047 }
2048 ++rowind_begin;
2049 ++value_begin;
2050 }
2051 ++input_dof_numbering_begin;
2052 }
2053 const size_t output_size = tmp_rowind.size();
2054 std::vector<std::pair<size_t, size_t>> output_dof_numbering(
2055 tmp_rowind.begin(), tmp_rowind.end());
2056 std::vector<std::pair<size_t, T>> output_col(output_size);
2057 for (size_t i = 0; i != output_size; ++i) {
2058 output_col[i].first = output_dof_numbering[i].first;
2059 }
2060 const Matrix<T, Mrectangle_increment_st_constref>& input_matrix = m_.m1.m2.m;
2061 const T scale_ = m_.scale * m_.m1.scale * m_.m1.m1.scale * m_.m2.scale;
2062 if (!new_output_matrix) {
2063 for (size_t j = 0; j != output_size; ++j) {
2064 size_t jj = output_dof_numbering[j].second;
2065 for (size_t i = 0; i != output_size; ++i) {
2066 output_col[i].second =
2067 scale_ * input_matrix(output_dof_numbering[i].second, jj);
2068 }
2069 add_colomn(output_dof_numbering[j].first, output_col.begin(), output_col.end());
2070 }
2071 } else {
2072 for (size_t i = 0; i != output_size; ++i) {
2073 tmp_rowind[output_dof_numbering[i].first] = i;
2074 }
2075 T* output_value = TemporaryBuffer<T>::get(output_size * input_size);
2076 T* output_value_l = output_value;
2077 for (size_t j = 0; j != input_size; ++j, output_value_l += output_size) {
2078 for (size_t i = 0; i != input_size; ++i) {
2079 const size_t* rowind_begin = rowind + colind[input_dof_numbering[i]];
2080 const size_t* const rowind_end = rowind + colind[input_dof_numbering[i] + 1];
2081 const T* value_begin = value_ + colind[input_dof_numbering[i]];
2082 const T v = scale_ * input_matrix(j, i);
2083 while (rowind_begin != rowind_end) {
2084 output_value_l[tmp_rowind[*rowind_begin++]] += *value_begin++ * v;
2085 }
2086 }
2087 }
2088 for (size_t i = 0; i != output_size; ++i) {
2089 for (size_t j = 0; j != output_size; ++j) { output_col[j].second = 0; }
2090 for (size_t j = 0; j != input_size; ++j) {
2091 const size_t* rowind_begin = rowind + colind[input_dof_numbering[j]];
2092 const size_t* const rowind_end = rowind + colind[input_dof_numbering[j] + 1];
2093 const T* value_begin = value_ + colind[input_dof_numbering[j]];
2094 const T v = output_value[i + j * output_size];
2095 while (rowind_begin != rowind_end) {
2096 output_col[tmp_rowind[*rowind_begin++]].second += *value_begin++ * v;
2097 }
2098 }
2099 add_colomn(output_dof_numbering[i].first, output_col.begin(), output_col.end());
2100 }
2101 std::fill_n(output_value, output_size * input_size, 0);
2102 }
2103 return *this;
2104 }
2105
2106 Matrix& operator+=(const Matrix<
2107 T, MMProd<
2108 MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>,
2109 Mcompressed_col_st_constref>>& m_) {
2111 return *this;
2112 }
2113
2114 Matrix& operator+=(
2115 const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
2116 if (size1() < m_.size1() || size2() < m_.size2()) {
2117 Exception() << "The two matrix do not have the same size, " << size() << " and "
2118 << m_.size() << THROW;
2119 }
2120
2121 if (m_.trans || m_.m1.trans) { UnimplementedError() << THROW; }
2122
2123 Matrix<T, Mcompressed_col> m_m2_tmp;
2124 if (m_.m2.trans) { m_m2_tmp = m_.m2; }
2125
2126 Matrix<T, Mcompressed_col_st_constref> m_m2(
2127 m_.m2.trans ? Matrix<T, Mcompressed_col_st_constref>(m_m2_tmp) : m_.m2);
2128
2129 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
2130 const size_t end_list_flag = m_.m1.size1();
2131 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
2132
2133 T scale = m_.scale * m_.m1.scale * m_m2.scale;
2134 const size_t* b_colind_begin = m_m2.si;
2135 const size_t* const b_colind_end = b_colind_begin + m_m2.size2();
2136 size_t end_list = end_list_flag;
2137 size_t col = 0;
2138 while (b_colind_begin != b_colind_end) {
2139 const size_t* b_rowind_begin = &m_m2.index[*b_colind_begin];
2140 const T* b_value_begin = &m_m2.m[*b_colind_begin];
2141 const size_t* const b_rowind_end = &m_m2.index[*++b_colind_begin];
2142 while (b_rowind_begin != b_rowind_end) {
2143 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
2144 const size_t* const a_rowind_end = m_.m1.index + m_.m1.si[*b_rowind_begin + 1];
2145 const T* a_value_begin = m_.m1.m + m_.m1.si[*b_rowind_begin++];
2146 const T b_value_begin_v = *b_value_begin++;
2147 while (a_rowind_begin != a_rowind_end) {
2148 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
2149 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
2150 tmp_index[*a_rowind_begin] = end_list;
2151 end_list = *a_rowind_begin;
2152 }
2153 ++a_rowind_begin;
2154 }
2155 }
2156 std::vector<std::pair<size_t, T>> res_tmp;
2157 while (end_list != end_list_flag) {
2158 res_tmp.push_back(std::pair<size_t, T>(end_list, scale * tmp_value[end_list]));
2159 const size_t end_list_next = tmp_index[end_list];
2160 tmp_index[end_list] = std::numeric_limits<size_t>::max();
2161 tmp_value[end_list] = T(0);
2162 end_list = end_list_next;
2163 }
2164
2165 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
2166 add_colomn(col++, res_tmp.begin(), res_tmp.end());
2167 }
2168 return *this;
2169 }
2170
2171 Matrix& operator-=(const Matrix& m_) {
2172 value_to_ccarray();
2173 const_cast<Matrix&>(m_).value_to_ccarray();
2174 blas::axpy(m.size(), -1, &m_.m[0], 1, &m[0], 1);
2175 return *this;
2176 }
2177
2178 Matrix& operator+=(const Matrix& m_) {
2179 value_to_ccarray();
2180 const_cast<Matrix&>(m_).value_to_ccarray();
2181 blas::axpy(m.size(), 1, &m_.m[0], 1, &m[0], 1);
2182 return *this;
2183 }
2184
2185 Matrix& operator+=(const Matrix<T, Mcompressed_col_st_constref>& m_) {
2186 if (m_.size1() != m_.size2()) { UnimplementedError() << THROW; }
2187 value_to_ccarray();
2188 if (m_.trans) { UnimplementedError() << THROW; }
2189 if (!std::equal(si.begin(), si.end(), m_.si)
2190 || !std::equal(
2191 index.begin() + si[0], index.begin() + si[size2()], m_.index + m_.si[0])) {
2192 if (si.back() == 0) {
2193 si.assign(m_.si, m_.si + m_.s2 + 1);
2194 index.assign(m_.index, m_.index + si.back());
2195 m.assign(m_.m, m_.m + si.back());
2196 blas::scal(m.size(), m_.scale, &m[0], 1);
2197 } else {
2198 size_t s_i = m_.si[0];
2199 size_t d_i = si[0];
2200 for (size_t j = 1; j != m_.s2 + 1; ++j) {
2201 const size_t s_i_end = m_.si[j];
2202 const size_t d_i_end = si[j];
2203 for (; d_i != d_i_end && s_i != s_i_end; ++d_i) {
2204 if (m_.index[s_i] == index[d_i]) { m[d_i] += m_.scale * m_.m[s_i++]; }
2205 }
2206 d_i = d_i_end;
2207 if (s_i != s_i_end) {
2208 if (s_i_end - s_i == 1 && m_.m[s_i] == T(0)) {
2209 ++s_i;
2210 } else {
2211 Exception() << THROW;
2212 }
2213 }
2214 }
2215 }
2216 } else {
2217 blas::axpy(m.size(), m_.scale, &m_.m[0], 1, &m[0], 1);
2218 }
2219 return *this;
2220 }
2221
2222 Matrix& operator=(
2223 const Matrix<T, Sum<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
2224 if (m_.size1() != m_.size2()) { UnimplementedError() << THROW; }
2225 if (m_.m1.trans || m_.m2.trans || !std::equal(m_.m1.si, m_.m1.si + m_.m1.s2 + 1, m_.m2.si)
2226 || !std::equal(
2227 m_.m1.index + m_.m1.si[0], m_.m1.index + m_.m1.si[m_.m1.s2],
2228 m_.m2.index + m_.m2.si[0])) {
2230 }
2231 si.clear();
2232 si.insert(si.begin(), m_.m1.si, m_.m1.si + m_.m1.s2 + 1);
2233 index.clear();
2234 index.insert(index.begin(), m_.m1.index + m_.m1.si[0], m_.m1.index + m_.m1.si[m_.m1.s2]);
2235 m.resize(index.size());
2236 for (size_t i = 0; i != m.size(); ++i) {
2237 m[i] = m_.scale * (m_.m1.scale * m_.m1.m[i] + m_.m2.scale * m_.m2.m[i]);
2238 }
2239 return *this;
2240 }
2241
2242 Matrix& operator*=(T s) {
2243 value_to_ccarray();
2244 blas::scal(m.size(), s, &m[0], 1);
2245 return *this;
2246 }
2247
2248 template <typename STORAGE>
2249 void scale(const Vector<T, STORAGE>& v_) {
2250 value_to_ccarray();
2251 size_t i = si[0];
2252 for (size_t j = 1; j != si.size(); ++j) {
2253 const size_t i_end = si[j];
2254 for (; i != i_end; ++i) { m[i] *= v_[j] * v_[index[i]]; }
2255 }
2256 }
2257
2258 void remove_empty_column(Index& index) {
2259 if (!si.empty()) { UnimplementedError() << THROW; }
2260 std::vector<std::vector<std::pair<size_t, T>>> value_tmp;
2261 index.clear();
2262 for (size_t i = 0; i != value.size(); ++i) {
2263 if (!value[i].empty()) {
2264 value_tmp.push_back(std::vector<std::pair<size_t, T>>());
2265 value_tmp.back().swap(value[i]);
2266 index.push_back(i);
2267 }
2268 }
2269 value.swap(value_tmp);
2270 value_to_ccarray();
2271 }
2272
2273 void remove_empty_column(Index& index, const double tol) {
2274 if (!si.empty()) { UnimplementedError() << THROW; }
2275 std::vector<std::vector<std::pair<size_t, T>>> value_tmp;
2276 index.clear();
2277 for (size_t i = 0; i != value.size(); ++i) {
2278 for (typename std::vector<std::pair<size_t, T>>::const_iterator j = value[i].begin();
2279 j != value[i].end(); ++j) {
2280 if (b2000::norm(j->second) > tol) {
2281 value_tmp.push_back(std::vector<std::pair<size_t, T>>());
2282 value_tmp.back().swap(value[i]);
2283 index.push_back(i);
2284 break;
2285 }
2286 }
2287 }
2288 value.swap(value_tmp);
2289 value_to_ccarray();
2290 }
2291
2292 void remove_zero(const double tol = 0) {
2293 value_to_ccarray();
2294 size_t i = si[0];
2295 size_t i_out = i;
2296 for (size_t j = 1; j != si.size(); ++j) {
2297 for (; i != si[j]; ++i) {
2298 if (b2000::norm(m[i]) > tol) {
2299 m[i_out] = m[i];
2300 index[i_out] = index[i];
2301 ++i_out;
2302 }
2303 }
2304 si[j] = i_out;
2305 }
2306 index.resize(i_out);
2307 m.resize(i_out);
2308 }
2309
2310 Vector<T, Vindex1_constref> get_diagonal() {
2311 set_diag_index();
2312 return Vector<T, Vindex1_constref>(
2313 diag_index.size(), &m[0], diag_index.back(), &diag_index[0]);
2314 }
2315
2316 void get_diagonal(Vector<T>& diag) {
2317 value_to_ccarray();
2318 diag.resize(si.size() - 1);
2319 for (size_t j = 0; j != diag.size(); ++j) { diag[j] = m[si[j]]; }
2320 }
2321
2322 Matrix<T, Mcompressed_col_update_sub_ref> operator()(const Interval& i, const Interval& j) {
2323 return Matrix<T, Mcompressed_col_update_sub_ref>(*this, i, j);
2324 }
2325
2326 operator const Matrix<T, Mcompressed_col_st_constref>() const {
2327 const_cast<Matrix*>(this)->value_to_ccarray();
2328 return Matrix<T, Mcompressed_col_st_constref>(
2329 s1, si.size() - 1, m.size(), &si[0], &index[0], &m[0], 1, false);
2330 }
2331
2332 friend logging::Logger& operator<<(logging::Logger& l, const Matrix& m) {
2333 const_cast<Matrix&>(m).value_to_ccarray();
2334 l << "column compressed matrix of size (" << m.size1() << ", " << m.size2() << ") ";
2335 l.write(m.si.size(), &m.si[0], 1, "colind");
2336 l << ", ";
2337 l.write(m.index.size(), &m.index[0], 1, "rowind");
2338 l << ", ";
2339 l.write(m.m.size(), &m.m[0], 1, "value");
2340 return l;
2341 }
2342
2343 size_t get_null_space_size() {
2344 if (si.size() <= 1) { return 0; }
2345 if (solver == 0) { return 0; }
2346 Matrix* noconst_this = const_cast<Matrix<T, Mcompressed_col_update_inv>*>(this);
2347 return noconst_this->solver->get_null_space_size();
2348 }
2349
2350 void get_null_space(Matrix<T, Mrectangle_ref> nks) {
2351 if (si.size() <= 1) { return; }
2352 Matrix* noconst_this = const_cast<Matrix<T, Mcompressed_col_update_inv>*>(this);
2353 noconst_this->value_to_ccarray();
2354 if (solver == 0) {
2355 noconst_this->solver = LU_sparse_solver<T>::new_default(connectivity, *dictionary);
2356 noconst_this->solver->init(
2357 si.size() - 1, index.size(), &si[0], &index[0], &m[0], connectivity, *dictionary);
2358 }
2359 noconst_this->solver->get_null_space(nks.size1(), nks.size2(), nks.m, nks.size1());
2360 }
2361
2362 static Matrix null;
2363
2364private:
2365 void set_diag_index() {
2366 value_to_ccarray();
2367 if (diag_index.empty()) {
2368 diag_index.resize(si.size() - 1);
2369 size_t i = si[0];
2370 for (size_t j = 0; j != diag_index.size(); ++j) {
2371 for (const size_t i_end = si[j + 1]; i != i_end; ++i) {
2372 if (index[i] == j) { diag_index[j] = i; }
2373 }
2374 }
2375 }
2376 }
2377
2378 bool value_to_ccarray() {
2379 if (value.empty()) {
2380 if (si.empty()) { si.push_back(0); }
2381 return false;
2382 }
2383 if (si.empty()) {
2384 diag_index.clear();
2385 si.reserve(value.size() + 1);
2386 si.push_back(0);
2387 typename std::vector<std::vector<std::pair<size_t, T>>>::const_iterator begin =
2388 value.begin();
2389 typename std::vector<std::vector<std::pair<size_t, T>>>::const_iterator end =
2390 value.end();
2391 size_t nnz = 0;
2392 for (; begin != end; ++begin) { nnz += begin->size(); }
2393 index.reserve(nnz);
2394 m.reserve(nnz);
2395 for (begin = value.begin(); begin != end; ++begin) {
2396 typename std::vector<std::pair<size_t, T>>::const_iterator i = begin->begin();
2397 typename std::vector<std::pair<size_t, T>>::const_iterator i_end = begin->end();
2398 for (; i != i_end; ++i) {
2399 index.push_back(i->first);
2400 m.push_back(i->second);
2401 }
2402 si.push_back(m.size());
2403 }
2404 } else {
2405 size_t nnz = 0;
2406 for (size_t j = 0; j != value.size(); ++j) {
2407 nnz += si[j + 1] - si[j] + value[j].size();
2408 }
2409 std::vector<size_t> si_tmp;
2410 si_tmp.reserve(si.size());
2411 si_tmp.push_back(0);
2412 std::vector<size_t> index_tmp;
2413 index_tmp.reserve(nnz);
2414 std::vector<T> m_tmp;
2415 m_tmp.reserve(nnz);
2416 for (size_t j = 0; j != value.size(); ++j) {
2417 size_t i = si[j];
2418 const size_t i_end = si[j + 1];
2419 if (!value[j].empty()) {
2420 typename std::vector<std::pair<size_t, T>>::const_iterator iv =
2421 value[j].begin();
2422 typename std::vector<std::pair<size_t, T>>::const_iterator iv_end =
2423 value[j].end();
2424 for (;;) {
2425 if (i == i_end || iv->first < index[i]) {
2426 index_tmp.push_back(iv->first);
2427 m_tmp.push_back(iv->second);
2428 if (++iv == iv_end) { break; }
2429 } else {
2430 index_tmp.push_back(index[i]);
2431 m_tmp.push_back(m[i]);
2432 ++i;
2433 }
2434 }
2435 }
2436 index_tmp.insert(index_tmp.end(), index.begin() + i, index.begin() + i_end);
2437 m_tmp.insert(m_tmp.end(), m.begin() + i, m.begin() + i_end);
2438 si_tmp.push_back(m_tmp.size());
2439 }
2440 si.swap(si_tmp);
2441 index.swap(index_tmp);
2442 m.swap(m_tmp);
2443 delete solver;
2444 solver = 0;
2445 value.clear();
2446 return true;
2447 }
2448 value.clear();
2449 return false;
2450 }
2451
2452 void resolve(
2453 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx, char left_or_right,
2454 Matrix<T, Mrectangle>& null_space, ssize_t max_null_space_vector) const {
2455 if (s == 0) { return; }
2456 Matrix* noconst_this = const_cast<Matrix<T, Mcompressed_col_update_inv>*>(this);
2457 noconst_this->value_to_ccarray();
2458 if (solver == 0) {
2459 noconst_this->solver = LU_sparse_solver<T>::new_default(connectivity, *dictionary);
2460 noconst_this->solver->init(
2461 si.size() - 1, index.size(), &si[0], &index[0], &m[0], connectivity, *dictionary);
2462 }
2463 noconst_this->solver->resolve(s, nrhs, b, ldb, x, ldx, left_or_right);
2464 }
2465
2466 void add_colomn(
2467 size_t col, typename std::vector<std::pair<size_t, T>>::const_iterator begin,
2468 typename std::vector<std::pair<size_t, T>>::const_iterator end) {
2469 if (begin == end) { return; }
2470
2471 if (si.empty()) {
2472 std::vector<std::pair<size_t, T>>& vcol = value[col];
2473 if (vcol.empty() || begin->first > vcol.back().first) {
2474 vcol.insert(vcol.end(), begin, end);
2475 } else {
2476 std::vector<std::pair<size_t, T>> tmp;
2477 tmp.reserve(vcol.size() + (end - begin));
2478 typename std::vector<std::pair<size_t, T>>::const_iterator vbegin = vcol.begin();
2479 typename std::vector<std::pair<size_t, T>>::const_iterator vend = vcol.end();
2480 while (vbegin != vend && begin != end) {
2481 if (vbegin->first < begin->first) {
2482 tmp.push_back(*vbegin++);
2483 } else if (vbegin->first > begin->first) {
2484 tmp.push_back(*begin++);
2485 } else {
2486 tmp.push_back(
2487 std::pair<size_t, T>(vbegin->first, vbegin->second + begin->second));
2488 ++begin;
2489 ++vbegin;
2490 }
2491 }
2492 tmp.insert(tmp.end(), vbegin, vend);
2493 tmp.insert(tmp.end(), begin, end);
2494 vcol.swap(tmp);
2495 }
2496 } else {
2497 size_t colind = si[col];
2498 T* beginv = &m[colind];
2499 size_t* begini = &index[colind];
2500 size_t* begini_end = &index[si[col + 1]];
2501 while (begini != begini_end) {
2502 if (*begini == begin->first) {
2503 *beginv += begin->second;
2504 if (++begin == end) { break; }
2505 }
2506 ++begini;
2507 ++beginv;
2508 }
2509 if (begin == end) { return; }
2510 {
2511 if (value.empty()) { value.resize(si.size() - 1); }
2512 std::vector<std::pair<size_t, T>>& vcol = value[col];
2513 beginv = &m[colind];
2514 begini = &index[colind];
2515 if (vcol.empty() || begin->first > vcol.back().first) {
2516 while (begin != end) {
2517 if (begini == begini_end || *begini > begin->first) {
2518 vcol.push_back(*begin++);
2519 } else {
2520 if (*begini == begin->first) { *beginv += (begin++)->second; }
2521 ++begini;
2522 ++beginv;
2523 }
2524 }
2525 } else {
2526 std::vector<std::pair<size_t, T>> tmp;
2527 tmp.reserve(vcol.size() + (end - begin));
2528 typename std::vector<std::pair<size_t, T>>::const_iterator vbegin =
2529 vcol.begin();
2530 typename std::vector<std::pair<size_t, T>>::const_iterator vend = vcol.end();
2531 while (begin != end) {
2532 if (begini == begini_end || *begini > begin->first) {
2533 while (vbegin != vend && vbegin->first < begin->first) {
2534 tmp.push_back(*vbegin++);
2535 }
2536 if (vbegin != vend) {
2537 if (vbegin->first > begin->first) {
2538 tmp.push_back(*begin);
2539 } else {
2540 tmp.push_back(std::pair<size_t, T>(
2541 vbegin->first, vbegin->second + begin->second));
2542 ++vbegin;
2543 }
2544 } else {
2545 tmp.push_back(*begin);
2546 }
2547 ++begin;
2548 } else {
2549 if (*begini == begin->first) { *beginv += (begin++)->second; }
2550 ++begini;
2551 ++beginv;
2552 }
2553 }
2554 tmp.insert(tmp.end(), vbegin, vend);
2555 vcol.swap(tmp);
2556 }
2557 }
2558 }
2559 }
2560
2561 size_t s1;
2562 std::vector<size_t> si;
2563 std::vector<T> m;
2564 std::vector<size_t> index;
2565 std::vector<size_t> diag_index;
2566 std::vector<std::vector<std::pair<size_t, T>>>
2567 value;
2569 LU_sparse_solver<T>* solver;
2570 SparseMatrixConnectivityType connectivity;
2571 const Dictionary* dictionary;
2572 MVFRIEND;
2573};
2574
2575template <typename T>
2576Matrix<T, Mcompressed_col_update_inv> Matrix<T, Mcompressed_col_update_inv>::null;
2577
2578struct Mcompressed_col_update_inv_ext {
2579 using copy = Mcompressed_col_update_inv;
2580 using inverse = Mcompressed_col_update_inv;
2581};
2582
2589template <typename T>
2590class Matrix<T, Mcompressed_col_update_inv_ext> : public Matrix<T, Mcompressed_col_update_inv> {
2591public:
2592 Matrix(
2593 size_t s1_ = 0, size_t size_ext_ = 0,
2594 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
2595 const Dictionary& dictionary_ = Dictionary::get_empty())
2596 : Matrix<T, Mcompressed_col_update_inv>(s1_, connectivity_, dictionary_),
2597 size_ext(size_ext_),
2598 solver(0) {}
2599
2600 Matrix(const Matrix& m_) : size_ext(m_.size_ext), solver(0) {}
2601
2602 ~Matrix() { delete solver; }
2603
2604 std::pair<size_t, size_t> size() const {
2605 return std::pair<size_t, size_t>(
2606 Matrix<T, Mcompressed_col_update_inv>::size1() + size_ext,
2607 Matrix<T, Mcompressed_col_update_inv>::size2() + size_ext);
2608 }
2609
2610 size_t size1() const { return Matrix<T, Mcompressed_col_update_inv>::size1() + size_ext; }
2611
2612 size_t size2() const { return Matrix<T, Mcompressed_col_update_inv>::size2() + size_ext; }
2613
2614 void resize(
2615 size_t s, size_t s_ext,
2616 SparseMatrixConnectivityType connectivity_ = sparse_matrix_connectivity_unknown,
2617 const Dictionary& dictionary_ = Dictionary::get_empty()) {
2618 Matrix<T, Mcompressed_col_update_inv>::resize(s, connectivity_, dictionary_);
2619 size_ext = s_ext;
2620 }
2621
2622 void set_zero() {
2623 Matrix<T, Mcompressed_col_update_inv>::set_zero();
2624 delete solver;
2625 solver = 0;
2626 }
2627
2628 void set_zero_same_struct() {
2629 Matrix<T, Mcompressed_col_update_inv>::set_zero_same_struct();
2630 if (solver) { solver->update_value(); }
2631 }
2632
2633 bool is_null() const { return this == &null; }
2634
2635 T operator()(size_t i, size_t j) const {
2636 if (i < Matrix<T, Mcompressed_col_update_inv>::size1()
2637 && j < Matrix<T, Mcompressed_col_update_inv>::size2()) {
2638 return Matrix<T, Mcompressed_col_update_inv>::operator()(i, j);
2639 }
2640 return 0;
2641 }
2642
2643 Matrix<T, Mcompressed_col_update_sub_ref> operator()(const Interval& i, const Interval& j) {
2644 return Matrix<T, Mcompressed_col_update_sub_ref>(*this, i, j);
2645 }
2646
2647 void resolve(
2648 size_t s, size_t nrhs, const T* b, size_t ldb, T* x, size_t ldx, const T* ma, const T* mb,
2649 const T* mc, char left_or_right, Matrix<T, Mrectangle>& null_space,
2650 ssize_t max_null_space_vector) const {
2651 Matrix* noconst_this = const_cast<Matrix<T, Mcompressed_col_update_inv_ext>*>(this);
2652 if (noconst_this->value_to_ccarray()) {
2653 delete noconst_this->solver;
2654 noconst_this->solver = 0;
2655 }
2656 if (solver == 0) {
2657 noconst_this->solver = LU_extension_sparse_solver<T>::new_default(
2658 Matrix<T, Mcompressed_col_update_inv>::connectivity,
2659 *Matrix<T, Mcompressed_col_update_inv>::dictionary);
2660 noconst_this->solver->init(
2661 Matrix<T, Mcompressed_col_update_inv>::si.size() - 1,
2662 Matrix<T, Mcompressed_col_update_inv>::index.size(),
2663 &Matrix<T, Mcompressed_col_update_inv>::si[0],
2664 &Matrix<T, Mcompressed_col_update_inv>::index[0],
2665 &Matrix<T, Mcompressed_col_update_inv>::m[0], size_ext,
2666 Matrix<T, Mcompressed_col_update_inv>::connectivity,
2667 *Matrix<T, Mcompressed_col_update_inv>::dictionary);
2668 }
2669 noconst_this->solver->resolve(s, nrhs, b, ldb, x, ldx, ma, mb, mc, left_or_right);
2670 }
2671
2672 static Matrix null;
2673
2674private:
2675 size_t size_ext;
2676 LU_extension_sparse_solver<T>* solver;
2677 MVFRIEND;
2678};
2679
2680template <typename T>
2681Matrix<T, Mcompressed_col_update_inv_ext> Matrix<T, Mcompressed_col_update_inv_ext>::null;
2682
2683struct Mcompressed_col_update_sub_ref {
2684 using copy = Mrectangle;
2685};
2686
2687template <typename T>
2688class Matrix<T, Mcompressed_col_update_sub_ref> {
2689public:
2690 Matrix(Matrix<T, Mcompressed_col_update_inv>& m_, const Interval& i_, const Interval& j_)
2691 : m(m_), i(i_), j(j_) {}
2692
2693 std::pair<size_t, size_t> size() const { return std::pair<size_t, size_t>(i.size(), j.size()); }
2694
2695 size_t size1() const { return i.size(); }
2696
2697 size_t size2() const { return j.size(); }
2698
2699 Matrix& operator+=(const Matrix<T, Mcompressed_col_constref>& m_) {
2700 if (size() != m_.size()) {
2701 Exception() << "The two matrix do not have the same size, " << size() << " and "
2702 << m_.size() << "." << THROW;
2703 }
2704 std::vector<std::pair<size_t, T>> res;
2705 size_t ii = m_.si[0];
2706 for (size_t jj = 0; jj != m_.size2(); ++jj) {
2707 const size_t ii_end = m_.si[jj + 1];
2708 res.clear();
2709 res.reserve(ii_end - ii);
2710 for (; ii != ii_end; ++ii) {
2711 res.push_back(std::pair<size_t, T>(i[0] + m_.index[ii], m_.m[ii]));
2712 }
2713 m.add_colomn(j[0] + jj, res.begin(), res.end());
2714 }
2715 return *this;
2716 }
2717
2718 Matrix& operator+=(
2719 const Matrix<T, MMProd<Mcompressed_col_st_constref, Mcompressed_col_st_constref>>& m_) {
2720 if (size() != m_.size()) {
2721 Exception() << "The two matrix do not have the same size, " << size() << " and "
2722 << m_.size() << "." << THROW;
2723 }
2724
2725 if (!(m_.trans || m_.m1.trans || m_.m2.trans)) {
2726 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
2727 const size_t end_list_flag = m_.m1.size1();
2728 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
2729
2730 const size_t* b_colind_begin = m_.m2.si;
2731 const size_t* const b_colind_end = b_colind_begin + m_.m2.size2();
2732 size_t end_list = end_list_flag;
2733 size_t col = j[0];
2734 while (b_colind_begin != b_colind_end) {
2735 const size_t* b_rowind_begin = &m_.m2.index[*b_colind_begin];
2736 const T* b_value_begin = &m_.m2.m[*b_colind_begin];
2737 const size_t* const b_rowind_end = &m_.m2.index[*++b_colind_begin];
2738 while (b_rowind_begin != b_rowind_end) {
2739 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
2740 const size_t* const a_rowind_end = m_.m1.index + m_.m1.si[*b_rowind_begin + 1];
2741 const T* a_value_begin = m_.m1.m + m_.m1.si[*b_rowind_begin++];
2742 const T b_value_begin_v = *b_value_begin++;
2743 while (a_rowind_begin != a_rowind_end) {
2744 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
2745 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
2746 tmp_index[*a_rowind_begin] = end_list;
2747 end_list = *a_rowind_begin;
2748 }
2749 ++a_rowind_begin;
2750 }
2751 }
2752 std::vector<std::pair<size_t, T>> res_tmp;
2753 while (end_list != end_list_flag) {
2754 res_tmp.push_back(std::pair<size_t, T>(i[end_list], tmp_value[end_list]));
2755 const size_t end_list_next = tmp_index[end_list];
2756 tmp_index[end_list] = std::numeric_limits<size_t>::max();
2757 tmp_value[end_list] = T(0);
2758 end_list = end_list_next;
2759 }
2760 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
2761 m.add_colomn(col++, res_tmp.begin(), res_tmp.end());
2762 }
2763 } else if (!m_.trans && m_.m1.trans && m_.m2.trans) {
2764 std::vector<std::vector<std::pair<size_t, T>>> res_tmp(j.size());
2765
2766 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m2.size2());
2767 const size_t end_list_flag = m_.m2.size2();
2768 T* tmp_value = TemporaryBuffer<T>::get(m_.m2.size2());
2769
2770 const size_t* b_colind_begin = m_.m1.si;
2771 const size_t* const b_colind_end = b_colind_begin + m_.m1.size1();
2772 size_t end_list = end_list_flag;
2773 size_t col = 0;
2774 while (b_colind_begin != b_colind_end) {
2775 const size_t* b_rowind_begin = &m_.m1.index[*b_colind_begin];
2776 const T* b_value_begin = &m_.m1.m[*b_colind_begin];
2777 const size_t* const b_rowind_end = &m_.m1.index[*++b_colind_begin];
2778 while (b_rowind_begin != b_rowind_end) {
2779 const size_t* a_rowind_begin = m_.m2.index + m_.m2.si[*b_rowind_begin];
2780 const size_t* const a_rowind_end = m_.m2.index + m_.m2.si[*b_rowind_begin + 1];
2781 const T* a_value_begin = m_.m2.m + m_.m2.si[*b_rowind_begin++];
2782 const T b_value_begin_v = *b_value_begin++;
2783 while (a_rowind_begin != a_rowind_end) {
2784 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
2785 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
2786 tmp_index[*a_rowind_begin] = end_list;
2787 end_list = *a_rowind_begin;
2788 }
2789 ++a_rowind_begin;
2790 }
2791 }
2792 while (end_list != end_list_flag) {
2793 res_tmp[end_list + j[0]].push_back(
2794 std::pair<size_t, T>(i[col], tmp_value[end_list]));
2795 const size_t end_list_next = tmp_index[end_list];
2796 tmp_index[end_list] = std::numeric_limits<size_t>::max();
2797 tmp_value[end_list] = T(0);
2798 end_list = end_list_next;
2799 }
2800 ++col;
2801 }
2802 for (size_t jj = 0; jj != res_tmp.size(); ++jj) {
2803 if (!res_tmp[jj].empty()) {
2804 std::sort(res_tmp[jj].begin(), res_tmp[jj].end(), CompareFirstOfPair());
2805 m.add_colomn(j[jj], res_tmp[jj].begin(), res_tmp[jj].end());
2806 }
2807 }
2808 } else if (!m_.trans && !m_.m1.trans && m_.m2.trans) {
2809 Matrix<T, Mcompressed_col> m_m2;
2810 m_m2 = m_.m2;
2811
2812 size_t* tmp_index = TemporaryBuffer<size_t>::get(m_.m1.size1());
2813 const size_t end_list_flag = m_.m1.size1();
2814 T* tmp_value = TemporaryBuffer<T>::get(m_.m1.size1());
2815
2816 T scale = m_.scale * m_.m1.scale;
2817 const size_t* b_colind_begin = &m_m2.si[0];
2818 const size_t* const b_colind_end = b_colind_begin + m_m2.size2();
2819 size_t end_list = end_list_flag;
2820 size_t col = 0;
2821 while (b_colind_begin != b_colind_end) {
2822 const size_t* b_rowind_begin = &m_m2.index[*b_colind_begin];
2823 const T* b_value_begin = &m_m2.m[*b_colind_begin];
2824 const size_t* const b_rowind_end = &m_m2.index[*++b_colind_begin];
2825 while (b_rowind_begin != b_rowind_end) {
2826 const size_t* a_rowind_begin = m_.m1.index + m_.m1.si[*b_rowind_begin];
2827 const size_t* const a_rowind_end =
2828 m_.m1.index + m_.m1.si[*b_rowind_begin++ + 1];
2829 while (a_rowind_begin != a_rowind_end && *a_rowind_begin < col) {
2830 ++a_rowind_begin;
2831 }
2832 const T* a_value_begin = m_.m1.m + (a_rowind_begin - m_.m1.index);
2833 const T b_value_begin_v = *b_value_begin++;
2834 while (a_rowind_begin != a_rowind_end) {
2835 tmp_value[*a_rowind_begin] += *a_value_begin++ * b_value_begin_v;
2836 if (!(std::numeric_limits<size_t>::max() - tmp_index[*a_rowind_begin])) {
2837 tmp_index[*a_rowind_begin] = end_list;
2838 end_list = *a_rowind_begin;
2839 }
2840 ++a_rowind_begin;
2841 }
2842 }
2843 std::vector<std::pair<size_t, T>> res_tmp;
2844 while (end_list != end_list_flag) {
2845 res_tmp.push_back(
2846 std::pair<size_t, T>(i[end_list], scale * tmp_value[end_list]));
2847 const size_t end_list_next = tmp_index[end_list];
2848 tmp_index[end_list] = std::numeric_limits<size_t>::max();
2849 tmp_value[end_list] = T(0);
2850 end_list = end_list_next;
2851 }
2852
2853 std::sort(res_tmp.begin(), res_tmp.end(), CompareFirstOfPair());
2854 m.add_colomn(j[col++], res_tmp.begin(), res_tmp.end());
2855 }
2856 } else {
2858 }
2859
2860 return *this;
2861 }
2862
2863private:
2864 Matrix<T, Mcompressed_col_update_inv>& m;
2865 const Interval& i;
2866 const Interval& j;
2867 MVFRIEND;
2868};
2869
2870} // namespace b2000::b2linalg
2871
2872#endif
bool operator==(const csda< T1 > &a, const csda< T2 > &b)
Comparison of two csda numbers is performed on the real part only.
Definition b2csda.H:226
#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
void scale_2(T1 v[2], const T2 s)
Definition b2tensor_calculus.H:297
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314