suanPan
🧮 An Open Source, Parallel and Heterogeneous Finite Element Analysis Framework
Loading...
Searching...
No Matches
triplet_form.hpp
Go to the documentation of this file.
1/*******************************************************************************
2 * Copyright (C) 2017-2026 Theodore Chang
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18#ifndef TRIPLET_FORM_HPP
19#define TRIPLET_FORM_HPP
20
21#include <Toolbox/utility.h>
22#include <numeric>
23
24template<sp_d data_t, sp_i index_t> class csc_form;
25template<sp_d data_t, sp_i index_t> class csr_form;
26
27enum class SparseBase : std::uint8_t {
28 ZERO,
29 ONE
30};
31
32template<sp_i index_t> class csr_comparator {
33 const index_t* const row_idx;
34 const index_t* const col_idx;
35
36public:
37 csr_comparator(const index_t* const in_row_idx, const index_t* const in_col_idx)
38 : row_idx(in_row_idx)
39 , col_idx(in_col_idx) {}
40
41 bool operator()(const index_t idx_a, const index_t idx_b) const {
42 if(row_idx[idx_a] == row_idx[idx_b]) return col_idx[idx_a] < col_idx[idx_b];
43 return row_idx[idx_a] < row_idx[idx_b];
44 }
45};
46
47template<sp_i index_t> class csc_comparator {
48 const index_t* const row_idx;
49 const index_t* const col_idx;
50
51public:
52 csc_comparator(const index_t* const in_row_idx, const index_t* const in_col_idx)
53 : row_idx(in_row_idx)
54 , col_idx(in_col_idx) {}
55
56 bool operator()(const index_t idx_a, const index_t idx_b) const {
57 if(col_idx[idx_a] == col_idx[idx_b]) return row_idx[idx_a] < row_idx[idx_b];
58 return col_idx[idx_a] < col_idx[idx_b];
59 }
60};
61
62template<sp_d data_t, sp_i index_t> class triplet_form final {
63 const data_t bin = data_t(0);
64
65 using index_ptr = std::unique_ptr<index_t[]>;
66 using data_ptr = std::unique_ptr<data_t[]>;
67
68 index_ptr row_idx = nullptr; // index storage
69 index_ptr col_idx = nullptr; // index storage
70 data_ptr val_idx = nullptr; // value storage
71
72 bool csc_sorted = false;
73 bool csr_sorted = false;
74
75 template<sp_d in_dt, sp_i in_it> void copy_to(const std::unique_ptr<in_it[]>& new_row_idx, const std::unique_ptr<in_it[]>& new_col_idx, const std::unique_ptr<in_dt[]>& new_val_idx, const index_t begin, const index_t row_offset, const index_t col_offset, const data_t scalar) const { copy_to(new_row_idx.get(), new_col_idx.get(), new_val_idx.get(), begin, row_offset, col_offset, scalar); }
76
77 template<sp_d in_dt, sp_i in_it> void copy_to(in_it* const new_row_idx, in_it* const new_col_idx, in_dt* const new_val_idx, const index_t begin, const index_t row_offset, const index_t col_offset, const data_t scalar) const {
78 suanpan::for_each(n_elem, [&](const index_t I) {
79 new_row_idx[I + begin] = in_it(row_idx[I] + row_offset);
80 new_col_idx[I + begin] = in_it(col_idx[I] + col_offset);
81 new_val_idx[I + begin] = in_dt(scalar * val_idx[I]);
82 });
83 }
84
88 void reserve(const index_t in_elem) {
89 if(in_elem <= n_alloc) return;
90
91 access::rw(n_alloc) = index_t(std::pow(2., std::ceil(std::log2(in_elem)) + 1));
92
93 index_ptr new_row_idx(new index_t[n_alloc]);
94 index_ptr new_col_idx(new index_t[n_alloc]);
95 data_ptr new_val_idx(new data_t[n_alloc]);
96
97 copy_to(new_row_idx, new_col_idx, new_val_idx, 0, 0, 0, 1);
98
99 row_idx = std::move(new_row_idx);
100 col_idx = std::move(new_col_idx);
101 val_idx = std::move(new_val_idx);
102 }
103
104 void invalidate_sorting_flag() { csc_sorted = csr_sorted = false; }
105
106 void condense(bool = false);
107
108 void populate_diagonal() {
109 const auto t_elem = std::min(n_rows, n_cols);
110 reserve(n_elem + t_elem);
111 suanpan::for_each(t_elem, [&](const index_t I) {
112 row_idx[n_elem + I] = I;
113 col_idx[n_elem + I] = I;
114 val_idx[n_elem + I] = data_t(0);
115 });
116 access::rw(n_elem) += t_elem;
117 invalidate_sorting_flag();
118 }
119
120public:
121 using data_type = data_t;
122 using index_type = index_t;
123
124 template<sp_d in_dt, sp_i in_it> friend class csc_form;
125 template<sp_d in_dt, sp_i in_it> friend class csr_form;
126 template<sp_d in_dt, sp_i in_it> friend class triplet_form;
127
128 const index_t n_rows = 0;
129 const index_t n_cols = 0;
130 const index_t n_elem = 0;
131 const index_t n_alloc = 0;
132
133 triplet_form() = default;
136 triplet_form& operator=(const triplet_form&);
137 triplet_form& operator=(triplet_form&&) noexcept;
138 ~triplet_form() = default;
139
140 triplet_form(const index_t in_rows, const index_t in_cols, const index_t in_elem = index_t(0))
141 : n_rows(in_rows)
142 , n_cols(in_cols) { init(in_elem); }
143
144 template<sp_d in_dt> explicit triplet_form(const SpMat<in_dt>&);
145 template<sp_d in_dt, sp_i in_it> explicit triplet_form(triplet_form<in_dt, in_it>&, SparseBase = SparseBase::ZERO, bool = false);
146
147 template<sp_d in_dt, sp_i in_it> explicit triplet_form(triplet_form<in_dt, in_it>&& in_mat, const SparseBase in_base = SparseBase::ZERO, const bool in_full = false)
148 : triplet_form(in_mat, in_base, in_full) {}
149
150 [[nodiscard]] const index_t* row_mem() const { return row_idx.get(); }
151
152 [[nodiscard]] const index_t* col_mem() const { return col_idx.get(); }
153
154 [[nodiscard]] const data_t* val_mem() const { return val_idx.get(); }
155
156 [[nodiscard]] index_t* row_mem() { return row_idx.get(); }
157
158 [[nodiscard]] index_t* col_mem() { return col_idx.get(); }
159
160 [[nodiscard]] data_t* val_mem() { return val_idx.get(); }
161
162 [[nodiscard]] index_t row(const index_t I) const { return row_idx[I]; }
163
164 [[nodiscard]] index_t col(const index_t I) const { return col_idx[I]; }
165
166 [[nodiscard]] data_t val(const index_t I) const { return val_idx[I]; }
167
168 [[nodiscard]] bool is_csr_sorted() const { return csr_sorted; }
169
170 [[nodiscard]] bool is_csc_sorted() const { return csc_sorted; }
171
172 [[nodiscard]] bool is_empty() const { return 0 == n_elem; }
173
174 [[nodiscard]] data_t max() const {
175 if(is_empty()) return data_t(0);
176 return *suanpan::max_element(val_idx.get(), val_idx.get() + n_elem);
177 }
178
179 void zeros() {
180 access::rw(n_elem) = 0;
181 invalidate_sorting_flag();
182 }
183
184 void init(const index_t in_elem) {
185 zeros();
186 reserve(in_elem);
187 }
188
189 void init(const index_t in_rows, const index_t in_cols, const index_t in_elem) {
190 access::rw(n_rows) = in_rows;
191 access::rw(n_cols) = in_cols;
192 init(in_elem);
193 }
194
195 data_t operator()(const index_t row, const index_t col) const {
196 for(index_t I = 0; I < n_elem; ++I)
197 if(row == row_idx[I] && col == col_idx[I]) return val_idx[I];
198 return access::rw(bin) = 0.;
199 }
200
201 data_t& at(index_t, index_t);
202
203 auto nullify(const index_t idx) {
204 suanpan::for_each(n_elem, [&](const auto I) {
205 if(idx == row(I) || idx == col(I)) val_mem()[I] = data_t(0);
206 });
207 }
208
221 void hack_size(const index_t in_elem) {
222 reserve(in_elem);
223 access::rw(n_elem) = in_elem;
224 }
225
226 void print() const;
227
228 void save(const std::string&) const;
229
230 void csr_sort();
231 void csc_sort();
232
234 csr_sort();
235 condense(false);
236 }
237
239 csc_sort();
240 condense(false);
241 }
242
244 populate_diagonal();
245 csr_sort();
246 condense(true);
247 }
248
250 populate_diagonal();
251 csc_sort();
252 condense(true);
253 }
254
255 void assemble(const Mat<data_t>&, const Col<uword>&);
256 template<sp_d in_dt, sp_i in_it> void assemble(const triplet_form<in_dt, in_it>&, index_t, index_t, data_t);
257
258 template<sp_d in_dt, sp_i in_it> void assemble(const triplet_form<in_dt, in_it>& in_mat, const std::vector<index_t>& row_shift, const std::vector<index_t>& col_shift, const std::vector<data_t>& scalar) {
259 suanpan_assert([&] { if(scalar.size() != row_shift.size() || scalar.size() != col_shift.size()) throw std::invalid_argument("size mismatch detected"); });
260
261 reserve(n_elem + index_t(scalar.size()) * index_t(in_mat.n_elem));
262
263 for(size_t I = 0; I < scalar.size(); ++I) assemble(in_mat, row_shift[I], col_shift[I], scalar[I]);
264 }
265
266 Mat<data_t> operator*(const Col<data_t>& in_mat) const {
267 Mat<data_t> out_mat(in_mat.n_rows, in_mat.n_cols, fill::zeros);
268
269 for(index_t I = 0; I < n_elem; ++I) out_mat(row_idx[I]) += val_idx[I] * in_mat(col_idx[I]);
270
271 return out_mat;
272 }
273
274 Mat<data_t> operator*(const Mat<data_t>& in_mat) const {
275 Mat<data_t> out_mat(in_mat.n_rows, in_mat.n_cols, fill::zeros);
276
277 for(index_t I = 0; I < n_elem; ++I) out_mat.row(row_idx[I]) += val_idx[I] * in_mat.row(col_idx[I]);
278
279 return out_mat;
280 }
281
282 template<sp_d T2> triplet_form operator*(T2) const;
283 template<sp_d T2> triplet_form operator/(T2) const;
284 template<sp_d T2> triplet_form& operator*=(T2);
285 template<sp_d T2> triplet_form& operator/=(T2);
286
287 triplet_form operator+(const triplet_form& in_mat) const {
288 triplet_form copy = *this;
289 // ReSharper disable once CppDFAUnusedValue
290 return copy += in_mat;
291 }
292
293 triplet_form operator-(const triplet_form& in_mat) const {
294 triplet_form copy = *this;
295 // ReSharper disable once CppDFAUnusedValue
296 return copy -= in_mat;
297 }
298
301
302 [[nodiscard]] Col<data_t> diag() const;
303 [[nodiscard]] triplet_form diagonal() const;
304 [[nodiscard]] triplet_form strictly_upper() const;
305 [[nodiscard]] triplet_form strictly_lower() const;
306 [[nodiscard]] triplet_form upper() const;
307 [[nodiscard]] triplet_form lower() const;
308};
309
310template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::condense(const bool full) {
311 if(n_elem < 2) return;
312
313 auto last_row = row_idx[0], last_col = col_idx[0];
314
315 sp_i auto current_pos = index_t(0);
316 sp_d auto last_sum = data_t(0);
317
318 auto populate = [&] {
319 if(suanpan::approx_equal(last_sum, data_t(0)) && (!full || last_row != last_col)) return;
320 row_idx[current_pos] = last_row;
321 col_idx[current_pos] = last_col;
322 val_idx[current_pos] = last_sum;
323 ++current_pos;
324 last_sum = data_t(0);
325 };
326
327 for(index_t I = 0; I < n_elem; ++I) {
328 if(last_row != row_idx[I] || last_col != col_idx[I]) {
329 populate();
330 last_row = row_idx[I];
331 last_col = col_idx[I];
332 }
333 last_sum += val_idx[I];
334 }
335
336 populate();
337
338 access::rw(n_elem) = current_pos;
339}
340
341template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>::triplet_form(const triplet_form& in_mat)
342 : csc_sorted{in_mat.csc_sorted}
343 , csr_sorted{in_mat.csr_sorted}
344 , n_rows{in_mat.n_rows}
345 , n_cols{in_mat.n_cols} {
346 init(in_mat.n_alloc);
347 in_mat.copy_to(row_idx, col_idx, val_idx, 0, 0, 0, 1);
348 access::rw(n_elem) = in_mat.n_elem;
349}
350
351template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>::triplet_form(triplet_form&& in_mat) noexcept
352 : row_idx{std::move(in_mat.row_idx)}
353 , col_idx{std::move(in_mat.col_idx)}
354 , val_idx{std::move(in_mat.val_idx)}
355 , csc_sorted{in_mat.csc_sorted}
356 , csr_sorted{in_mat.csr_sorted}
357 , n_rows{in_mat.n_rows}
358 , n_cols{in_mat.n_cols}
359 , n_elem{in_mat.n_elem}
360 , n_alloc{in_mat.n_alloc} {}
361
363 if(this == &in_mat) return *this;
364 csc_sorted = in_mat.csc_sorted;
365 csr_sorted = in_mat.csr_sorted;
366 access::rw(n_rows) = in_mat.n_rows;
367 access::rw(n_cols) = in_mat.n_cols;
368 init(in_mat.n_alloc);
369 in_mat.copy_to(row_idx, col_idx, val_idx, 0, 0, 0, 1);
370 access::rw(n_elem) = in_mat.n_elem;
371 return *this;
372}
373
374template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>& triplet_form<data_t, index_t>::operator=(triplet_form&& in_mat) noexcept {
375 if(this == &in_mat) return *this;
376 csc_sorted = in_mat.csc_sorted;
377 csr_sorted = in_mat.csr_sorted;
378 access::rw(n_rows) = in_mat.n_rows;
379 access::rw(n_cols) = in_mat.n_cols;
380 access::rw(n_elem) = in_mat.n_elem;
381 access::rw(n_alloc) = in_mat.n_alloc;
382 row_idx = std::move(in_mat.row_idx);
383 col_idx = std::move(in_mat.col_idx);
384 val_idx = std::move(in_mat.val_idx);
385 return *this;
386}
387
388template<sp_d data_t, sp_i index_t> template<sp_d in_dt> triplet_form<data_t, index_t>::triplet_form(const SpMat<in_dt>& in_mat)
389 : n_rows(index_t(in_mat.n_rows))
390 , n_cols(index_t(in_mat.n_cols)) {
391 init(index_t(in_mat.n_nonzero));
392
393 for(auto I = in_mat.begin(); I != in_mat.end(); ++I) at(I.row(), I.col()) = *I;
394}
395
396template<sp_d data_t, sp_i index_t> template<sp_d in_dt, sp_i in_it> triplet_form<data_t, index_t>::triplet_form(triplet_form<in_dt, in_it>& in_mat, const SparseBase base, const bool full)
397 : csc_sorted(in_mat.csc_sorted)
398 , csr_sorted(in_mat.csr_sorted)
399 , n_rows(index_t(in_mat.n_rows))
400 , n_cols(index_t(in_mat.n_cols)) {
401 if(in_mat.is_empty()) return;
402
403 init(index_t(in_mat.n_alloc));
404
405 if(full) in_mat.full_csc_condense();
406 else in_mat.csc_condense();
407
408 const sp_i auto shift = index_t(base);
409
410 in_mat.copy_to(row_idx, col_idx, val_idx, 0, shift, shift, 1);
411
412 access::rw(n_elem) = index_t(in_mat.n_elem);
413}
414
415template<sp_d data_t, sp_i index_t> data_t& triplet_form<data_t, index_t>::at(const index_t row, const index_t col) {
416 suanpan_assert([&] { if(row >= n_rows || col >= n_cols) throw std::invalid_argument("inconsistent size"); });
417
418 invalidate_sorting_flag();
419 reserve(n_elem + 1);
420 row_idx[n_elem] = row;
421 col_idx[n_elem] = col;
422 return val_idx[access::rw(n_elem)++] = data_t(0);
423}
424
425template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::print() const {
426 suanpan_info("A sparse matrix in triplet form with size of {} by {}, the density of {:.3f}%.\n", n_rows, n_cols, static_cast<double>(n_elem) / static_cast<double>(n_rows) / static_cast<double>(n_cols) * 1E2);
427 if(n_elem > index_t(1000)) {
428 suanpan_info("More than 1000 elements exist.\n");
429 return;
430 }
431 for(index_t I = 0; I < n_elem; ++I)
432 suanpan_info("({}, {}) ===> {:+.8E}\n", row_idx[I], col_idx[I], val_idx[I]);
433}
434
451template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::save(const std::string& file_name) const {
452 std::ofstream file(file_name);
453 if(!file.is_open()) return;
454 file << suanpan::format("{} {} {}\n", n_rows, n_cols, n_elem);
455 for(index_t I = 0; I < n_elem; ++I) file << suanpan::format("{} {} {}\n", row_idx[I], col_idx[I], val_idx[I]);
456 file.close();
457}
458
472template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::csr_sort() {
473 if(csr_sorted) return;
474
475 std::vector<index_t> index(n_elem);
476 std::iota(index.begin(), index.end(), index_t(0));
477
478 suanpan_sort(index.begin(), index.end(), csr_comparator<index_t>(row_idx.get(), col_idx.get()));
479
480 index_ptr new_row_idx(new index_t[n_alloc]);
481 index_ptr new_col_idx(new index_t[n_alloc]);
482 data_ptr new_val_idx(new data_t[n_alloc]);
483
484 suanpan::for_each(n_elem, [&](const index_t I) {
485 new_row_idx[I] = row_idx[index[I]];
486 new_col_idx[I] = col_idx[index[I]];
487 new_val_idx[I] = val_idx[index[I]];
488 });
489
490 row_idx = std::move(new_row_idx);
491 col_idx = std::move(new_col_idx);
492 val_idx = std::move(new_val_idx);
493
494 csr_sorted = true;
495 csc_sorted = false;
496}
497
511template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::csc_sort() {
512 if(csc_sorted) return;
513
514 std::vector<index_t> index(n_elem);
515 std::iota(index.begin(), index.end(), index_t(0));
516
517 suanpan_sort(index.begin(), index.end(), csc_comparator<index_t>(row_idx.get(), col_idx.get()));
518
519 index_ptr new_row_idx(new index_t[n_alloc]);
520 index_ptr new_col_idx(new index_t[n_alloc]);
521 data_ptr new_val_idx(new data_t[n_alloc]);
522
523 suanpan::for_each(n_elem, [&](const index_t I) {
524 new_row_idx[I] = row_idx[index[I]];
525 new_col_idx[I] = col_idx[index[I]];
526 new_val_idx[I] = val_idx[index[I]];
527 });
528
529 row_idx = std::move(new_row_idx);
530 col_idx = std::move(new_col_idx);
531 val_idx = std::move(new_val_idx);
532
533 csc_sorted = true;
534 csr_sorted = false;
535}
536
537template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::assemble(const Mat<data_t>& in_mat, const Col<uword>& in_dof) {
538 if(in_mat.empty()) return;
539
540 invalidate_sorting_flag();
541
542 const auto t_elem = n_elem + index_t(in_mat.n_elem);
543
544 reserve(t_elem);
545
546 suanpan::for_each(in_mat.n_elem, [&](const uword I) {
547 row_idx[n_elem + I] = index_t(in_dof(I % in_dof.n_elem));
548 col_idx[n_elem + I] = index_t(in_dof(I / in_dof.n_elem));
549 val_idx[n_elem + I] = in_mat(I);
550 });
551
552 access::rw(n_elem) = t_elem;
553}
554
555template<sp_d data_t, sp_i index_t> template<sp_d in_dt, sp_i in_it> void triplet_form<data_t, index_t>::assemble(const triplet_form<in_dt, in_it>& in_mat, const index_t row_shift, const index_t col_shift, const data_t scalar) {
556 if(in_mat.is_empty()) return;
557
558 invalidate_sorting_flag();
559
560 const auto t_elem = n_elem + in_mat.n_elem;
561
562 reserve(t_elem);
563
564 in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, row_shift, col_shift, scalar);
565
566 access::rw(n_elem) = t_elem;
567}
568
569template<sp_d data_t, sp_i index_t> template<sp_d T2> triplet_form<data_t, index_t> triplet_form<data_t, index_t>::operator*(const T2 scalar) const {
570 if(suanpan::approx_equal(T2(0), scalar)) return triplet_form(n_rows, n_cols);
571
572 auto copy = *this;
573
574 if(suanpan::approx_equal(T2(1), scalar)) return copy;
575
576 if(suanpan::approx_equal(T2(-1), scalar))
577 suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [](data_t& I) { I = -I; });
578 else
579 suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [=](data_t& I) { I *= data_t(scalar); });
580
581 return copy;
582}
583
584template<sp_d data_t, sp_i index_t> template<sp_d T2> triplet_form<data_t, index_t> triplet_form<data_t, index_t>::operator/(const T2 scalar) const {
585 auto copy = *this;
586
587 if(suanpan::approx_equal(T2(1), scalar)) return copy;
588
589 if(suanpan::approx_equal(T2(-1), scalar))
590 suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [](data_t& I) { I = -I; });
591 else
592 suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [=](data_t& I) { I /= data_t(scalar); });
593
594 return copy;
595}
596
597template<sp_d data_t, sp_i index_t> template<sp_d T2> triplet_form<data_t, index_t>& triplet_form<data_t, index_t>::operator*=(const T2 scalar) {
598 if(suanpan::approx_equal(T2(1), scalar)) return *this;
599
600 if(suanpan::approx_equal(T2(0), scalar)) zeros();
601 else if(suanpan::approx_equal(T2(-1), scalar))
602 suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [](data_t& I) { I = -I; });
603 else
604 suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [=](data_t& I) { I *= data_t(scalar); });
605
606 return *this;
607}
608
609template<sp_d data_t, sp_i index_t> template<sp_d T2> triplet_form<data_t, index_t>& triplet_form<data_t, index_t>::operator/=(const T2 scalar) {
610 if(suanpan::approx_equal(T2(1), scalar)) return *this;
611
612 if(suanpan::approx_equal(T2(-1), scalar))
613 suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [](data_t& I) { I = -I; });
614 else
615 suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [=](data_t& I) { I /= data_t(scalar); });
616
617 return *this;
618}
619
621 if(in_mat.is_empty()) return *this;
622
623 invalidate_sorting_flag();
624
625 const auto t_elem = n_elem + index_t(in_mat.n_elem);
626
627 reserve(t_elem);
628
629 in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, 0, 0, 1);
630
631 access::rw(n_elem) = t_elem;
632
633 return *this;
634}
635
637 if(in_mat.is_empty()) return *this;
638
639 invalidate_sorting_flag();
640
641 const auto t_elem = n_elem + index_t(in_mat.n_elem);
642
643 reserve(t_elem);
644
645 in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, 0, 0, -1);
646
647 access::rw(n_elem) = t_elem;
648
649 return *this;
650}
651
652template<sp_d data_t, sp_i index_t> Col<data_t> triplet_form<data_t, index_t>::diag() const {
653 Col<data_t> diag_vec(std::min(n_rows, n_cols), fill::zeros);
654 for(index_t I = 0; I < n_elem; ++I)
655 if(row(I) == col(I)) diag_vec(row(I)) += val(I);
656 return diag_vec;
657}
658
660 auto out_mat = *this;
661
662 suanpan::for_each(out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.row(I) == out_mat.col(I); });
663
664 return out_mat;
665}
666
668 auto out_mat = *this;
669
670 suanpan::for_each(out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.row(I) < out_mat.col(I); });
671
672 return out_mat;
673}
674
676 auto out_mat = *this;
677
678 suanpan::for_each(out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.col(I) < out_mat.row(I); });
679
680 return out_mat;
681}
682
683template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t> triplet_form<data_t, index_t>::upper() const {
684 auto out_mat = *this;
685
686 suanpan::for_each(out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.row(I) <= out_mat.col(I); });
687
688 return out_mat;
689}
690
691template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t> triplet_form<data_t, index_t>::lower() const {
692 auto out_mat = *this;
693
694 suanpan::for_each(out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.col(I) <= out_mat.row(I); });
695
696 return out_mat;
697}
698
699template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t> operator+(const triplet_form<data_t, index_t>& mat_a, const triplet_form<data_t, index_t>& mat_b) {
700 auto out = mat_a;
701 out += mat_b;
702 return out;
703}
704
706 mat_a += mat_b;
707 return std::move(mat_a);
708}
709
711 mat_b += mat_a;
712 return std::move(mat_b);
713}
714
716 mat_a += mat_b;
717 return std::move(mat_a);
718}
719
720#endif
Storage< T >::iterator begin(Storage< T > &S)
Definition Storage.hpp:209
Definition triplet_form.hpp:47
bool operator()(const index_t idx_a, const index_t idx_b) const
Definition triplet_form.hpp:56
csc_comparator(const index_t *const in_row_idx, const index_t *const in_col_idx)
Definition triplet_form.hpp:52
Definition csc_form.hpp:25
Definition triplet_form.hpp:32
bool operator()(const index_t idx_a, const index_t idx_b) const
Definition triplet_form.hpp:41
csr_comparator(const index_t *const in_row_idx, const index_t *const in_col_idx)
Definition triplet_form.hpp:37
Definition csr_form.hpp:25
Definition triplet_form.hpp:62
void csr_sort()
Sorts the COO format into the CSR (Compressed Sparse Row) order.
Definition triplet_form.hpp:472
data_t data_type
Definition triplet_form.hpp:121
triplet_form strictly_lower() const
Definition triplet_form.hpp:675
triplet_form operator+(const triplet_form &in_mat) const
Definition triplet_form.hpp:287
void zeros()
Definition triplet_form.hpp:179
data_t * val_mem()
Definition triplet_form.hpp:160
void assemble(const triplet_form< in_dt, in_it > &, index_t, index_t, data_t)
Definition triplet_form.hpp:555
triplet_form()=default
triplet_form(triplet_form< in_dt, in_it > &&in_mat, const SparseBase in_base=SparseBase::ZERO, const bool in_full=false)
Definition triplet_form.hpp:147
const index_t n_rows
Definition triplet_form.hpp:128
void save(const std::string &) const
Saves the triplet form matrix to a file.
Definition triplet_form.hpp:451
triplet_form upper() const
Definition triplet_form.hpp:683
const index_t n_alloc
Definition triplet_form.hpp:131
data_t max() const
Definition triplet_form.hpp:174
void hack_size(const index_t in_elem)
Adjusts the size of the container by reserving space and updating the element count.
Definition triplet_form.hpp:221
void csc_condense()
Definition triplet_form.hpp:238
void csc_sort()
Sorts the COO format into the CSC (Compressed Sparse Column) order.
Definition triplet_form.hpp:511
triplet_form strictly_upper() const
Definition triplet_form.hpp:667
Mat< data_t > operator*(const Mat< data_t > &in_mat) const
Definition triplet_form.hpp:274
triplet_form(triplet_form &&) noexcept
Definition triplet_form.hpp:351
triplet_form diagonal() const
Definition triplet_form.hpp:659
triplet_form lower() const
Definition triplet_form.hpp:691
bool is_empty() const
Definition triplet_form.hpp:172
data_t & at(index_t, index_t)
Definition triplet_form.hpp:415
void full_csr_condense()
Definition triplet_form.hpp:243
void csr_condense()
Definition triplet_form.hpp:233
bool is_csc_sorted() const
Definition triplet_form.hpp:170
triplet_form(const SpMat< in_dt > &)
Definition triplet_form.hpp:388
triplet_form(const triplet_form &)
Definition triplet_form.hpp:341
triplet_form & operator-=(const triplet_form &)
Definition triplet_form.hpp:636
index_t * row_mem()
Definition triplet_form.hpp:156
triplet_form & operator=(const triplet_form &)
Definition triplet_form.hpp:362
triplet_form & operator+=(const triplet_form &)
Definition triplet_form.hpp:620
index_t * col_mem()
Definition triplet_form.hpp:158
data_t operator()(const index_t row, const index_t col) const
Definition triplet_form.hpp:195
const index_t n_cols
Definition triplet_form.hpp:129
triplet_form operator-(const triplet_form &in_mat) const
Definition triplet_form.hpp:293
triplet_form & operator/=(T2)
const data_t * val_mem() const
Definition triplet_form.hpp:154
triplet_form operator*(T2) const
Mat< data_t > operator*(const Col< data_t > &in_mat) const
Definition triplet_form.hpp:266
void init(const index_t in_rows, const index_t in_cols, const index_t in_elem)
Definition triplet_form.hpp:189
const index_t n_elem
Definition triplet_form.hpp:130
triplet_form & operator*=(T2)
void init(const index_t in_elem)
Definition triplet_form.hpp:184
const index_t * row_mem() const
Definition triplet_form.hpp:150
triplet_form operator/(T2) const
void print() const
Definition triplet_form.hpp:425
auto nullify(const index_t idx)
Definition triplet_form.hpp:203
Col< data_t > diag() const
Definition triplet_form.hpp:652
friend class triplet_form
Definition triplet_form.hpp:126
bool is_csr_sorted() const
Definition triplet_form.hpp:168
void assemble(const triplet_form< in_dt, in_it > &in_mat, const std::vector< index_t > &row_shift, const std::vector< index_t > &col_shift, const std::vector< data_t > &scalar)
Definition triplet_form.hpp:258
index_t col(const index_t I) const
Definition triplet_form.hpp:164
data_t val(const index_t I) const
Definition triplet_form.hpp:166
void assemble(const Mat< data_t > &, const Col< uword > &)
Definition triplet_form.hpp:537
const index_t * col_mem() const
Definition triplet_form.hpp:152
index_t row(const index_t I) const
Definition triplet_form.hpp:162
void full_csc_condense()
Definition triplet_form.hpp:249
triplet_form(triplet_form< in_dt, in_it > &, SparseBase=SparseBase::ZERO, bool=false)
Definition triplet_form.hpp:396
index_t index_type
Definition triplet_form.hpp:122
Definition suanPan.h:357
Definition suanPan.h:358
bool approx_equal(const T x, const T y, int ulp=2)
Definition utility.h:97
std::string format(const std::string_view format_str, const T &... args)
Definition suanPan.h:302
constexpr T max_element(T start, T end)
Definition utility.h:42
void for_each(const IT start, const IT end, F &&FN)
Definition utility.h:31
#define suanpan_info
Definition suanPan.h:345
auto suanpan_assert(F &&handler)
Definition suanPan.h:339
#define suanpan_for_each
Definition suanPan.h:181
#define suanpan_sort
Definition suanPan.h:180
SparseBase
Definition triplet_form.hpp:27
triplet_form< data_t, index_t > operator+(const triplet_form< data_t, index_t > &mat_a, const triplet_form< data_t, index_t > &mat_b)
Definition triplet_form.hpp:699