suanPan
triplet_form.hpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (C) 2017-2022 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 
24 template<sp_d data_t, sp_i index_t> class csc_form;
25 template<sp_d data_t, sp_i index_t> class csr_form;
26 
27 enum class SparseBase : short unsigned {
28  ZERO,
29  ONE
30 };
31 
32 template<sp_i index_t> class csr_comparator {
33  const index_t* const row_idx;
34  const index_t* const col_idx;
35 
36 public:
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 
47 template<sp_i index_t> class csc_comparator {
48  const index_t* const row_idx;
49  const index_t* const col_idx;
50 
51 public:
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 
62 template<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(index_t(0), 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(index_t(0), 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 
120 public:
121  typedef data_t data_type;
122  typedef index_t index_type;
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  [[nodiscard]] const index_t* row_mem() const { return row_idx.get(); }
148 
149  [[nodiscard]] const index_t* col_mem() const { return col_idx.get(); }
150 
151  [[nodiscard]] const data_t* val_mem() const { return val_idx.get(); }
152 
153  [[nodiscard]] index_t* row_mem() { return row_idx.get(); }
154 
155  [[nodiscard]] index_t* col_mem() { return col_idx.get(); }
156 
157  [[nodiscard]] data_t* val_mem() { return val_idx.get(); }
158 
159  [[nodiscard]] index_t row(const index_t I) const { return row_idx[I]; }
160 
161  [[nodiscard]] index_t col(const index_t I) const { return col_idx[I]; }
162 
163  [[nodiscard]] data_t val(const index_t I) const { return val_idx[I]; }
164 
165  [[nodiscard]] bool is_csr_sorted() const { return csr_sorted; }
166 
167  [[nodiscard]] bool is_csc_sorted() const { return csc_sorted; }
168 
169  [[nodiscard]] bool is_empty() const { return 0 == n_elem; }
170 
171  [[nodiscard]] data_t max() const {
172  if(is_empty()) return data_t(0);
173  return *std::max_element(val_idx.get(), val_idx.get() + n_elem);
174  }
175 
176  void zeros() {
177  access::rw(n_elem) = 0;
178  invalidate_sorting_flag();
179  }
180 
181  void init(const index_t in_elem) {
182  zeros();
183  reserve(in_elem);
184  }
185 
186  void init(const index_t in_rows, const index_t in_cols, const index_t in_elem) {
187  access::rw(n_rows) = in_rows;
188  access::rw(n_cols) = in_cols;
189  init(in_elem);
190  }
191 
192  const data_t& operator()(const index_t row, const index_t col) const {
193  for(index_t I = 0; I < n_elem; ++I) if(row == row_idx[I] && col == col_idx[I]) return val_idx[I];
194  return access::rw(bin) = 0.;
195  }
196 
197  data_t& at(index_t, index_t);
198 
199  void print() const;
200 
201  void csr_sort();
202  void csc_sort();
203 
204  void csr_condense() {
205  csr_sort();
206  condense(false);
207  }
208 
209  void csc_condense() {
210  csc_sort();
211  condense(false);
212  }
213 
215  populate_diagonal();
216  csr_sort();
217  condense(true);
218  }
219 
221  populate_diagonal();
222  csc_sort();
223  condense(true);
224  }
225 
226  void assemble(const Mat<data_t>&, const Col<uword>&);
227  template<sp_d in_dt, sp_i in_it> void assemble(const triplet_form<in_dt, in_it>&, index_t, index_t, data_t);
228 
229  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) {
230  suanpan_debug([&] { if(scalar.size() != row_shift.size() || scalar.size() != col_shift.size()) throw invalid_argument("size mismatch detected"); });
231 
232  reserve(n_elem + index_t(scalar.size()) * index_t(in_mat.n_elem));
233 
234  for(size_t I = 0; I < scalar.size(); ++I) assemble(in_mat, row_shift[I], col_shift[I], scalar[I]);
235  }
236 
237  Mat<data_t> operator*(const Col<data_t>& in_mat) const {
238  Mat<data_t> out_mat(in_mat.n_rows, in_mat.n_cols, fill::zeros);
239 
240  for(index_t I = 0; I < n_elem; ++I) out_mat(row_idx[I]) += val_idx[I] * in_mat(col_idx[I]);
241 
242  return out_mat;
243  }
244 
245  Mat<data_t> operator*(const Mat<data_t>& in_mat) const {
246  Mat<data_t> out_mat(in_mat.n_rows, in_mat.n_cols, fill::zeros);
247 
248  for(index_t I = 0; I < n_elem; ++I) out_mat.row(row_idx[I]) += val_idx[I] * in_mat.row(col_idx[I]);
249 
250  return out_mat;
251  }
252 
253  template<sp_d T2> triplet_form<data_t, index_t> operator*(T2) const;
254  template<sp_d T2> triplet_form<data_t, index_t> operator/(T2) const;
257 
259  triplet_form<data_t, index_t> copy = *this;
260  return copy += in_mat;
261  }
262 
264  triplet_form<data_t, index_t> copy = *this;
265  return copy -= in_mat;
266  }
267 
270 
271  [[nodiscard]] Col<data_t> diag() const;
275 };
276 
277 template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::condense(const bool full) {
278  if(n_elem < 2) return;
279 
280  auto last_row = row_idx[0], last_col = col_idx[0];
281 
282  sp_i auto current_pos = index_t(0);
283  sp_d auto last_sum = data_t(0);
284 
285  auto populate = [&] {
286  if(suanpan::approx_equal(last_sum, data_t(0)) && (!full || last_row != last_col)) return;
287  row_idx[current_pos] = last_row;
288  col_idx[current_pos] = last_col;
289  val_idx[current_pos] = last_sum;
290  ++current_pos;
291  last_sum = data_t(0);
292  };
293 
294  for(index_t I = 0; I < n_elem; ++I) {
295  if(last_row != row_idx[I] || last_col != col_idx[I]) {
296  populate();
297  last_row = row_idx[I];
298  last_col = col_idx[I];
299  }
300  last_sum += val_idx[I];
301  }
302 
303  populate();
304 
305  access::rw(n_elem) = current_pos;
306 }
307 
308 template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>::triplet_form(const triplet_form& in_mat)
309  : csc_sorted{in_mat.csc_sorted}
310  , csr_sorted{in_mat.csr_sorted}
311  , n_rows{in_mat.n_rows}
312  , n_cols{in_mat.n_cols} {
313  init(in_mat.n_alloc);
314  in_mat.copy_to(row_idx, col_idx, val_idx, 0, 0, 0, 1);
315  access::rw(n_elem) = in_mat.n_elem;
316 }
317 
318 template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>::triplet_form(triplet_form&& in_mat) noexcept
319  : row_idx{std::move(in_mat.row_idx)}
320  , col_idx{std::move(in_mat.col_idx)}
321  , val_idx{std::move(in_mat.val_idx)}
322  , csc_sorted{in_mat.csc_sorted}
323  , csr_sorted{in_mat.csr_sorted}
324  , n_rows{in_mat.n_rows}
325  , n_cols{in_mat.n_cols}
326  , n_elem{in_mat.n_elem}
327  , n_alloc{in_mat.n_alloc} {}
328 
329 template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t>& triplet_form<data_t, index_t>::operator=(const triplet_form& in_mat) {
330  if(this == &in_mat) return *this;
331  csc_sorted = in_mat.csc_sorted;
332  csr_sorted = in_mat.csr_sorted;
333  access::rw(n_rows) = in_mat.n_rows;
334  access::rw(n_cols) = in_mat.n_cols;
335  init(in_mat.n_alloc);
336  in_mat.copy_to(row_idx, col_idx, val_idx, 0, 0, 0, 1);
337  access::rw(n_elem) = in_mat.n_elem;
338  return *this;
339 }
340 
341 template<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 {
342  if(this == &in_mat) return *this;
343  csc_sorted = in_mat.csc_sorted;
344  csr_sorted = in_mat.csr_sorted;
345  access::rw(n_rows) = in_mat.n_rows;
346  access::rw(n_cols) = in_mat.n_cols;
347  access::rw(n_elem) = in_mat.n_elem;
348  access::rw(n_alloc) = in_mat.n_alloc;
349  row_idx = std::move(in_mat.row_idx);
350  col_idx = std::move(in_mat.col_idx);
351  val_idx = std::move(in_mat.val_idx);
352  return *this;
353 }
354 
355 template<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)
356  : n_rows(index_t(in_mat.n_rows))
357  , n_cols(index_t(in_mat.n_cols)) {
358  init(index_t(in_mat.n_nonzero));
359 
360  for(auto I = in_mat.begin(); I != in_mat.end(); ++I) at(I.row(), I.col()) = *I;
361 }
362 
363 template<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)
364  : csc_sorted(in_mat.csc_sorted)
365  , csr_sorted(in_mat.csr_sorted)
366  , n_rows(index_t(in_mat.n_rows))
367  , n_cols(index_t(in_mat.n_cols)) {
368  if(in_mat.is_empty()) return;
369 
370  init(index_t(in_mat.n_alloc));
371 
372  if(full) in_mat.full_csc_condense();
373  else in_mat.csc_condense();
374 
375  const sp_i auto shift = index_t(base);
376 
377  in_mat.copy_to(row_idx, col_idx, val_idx, 0, shift, shift, 1);
378 
379  access::rw(n_elem) = index_t(in_mat.n_elem);
380 }
381 
382 template<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) {
383  suanpan_debug([&] { if(row >= n_rows || col >= n_cols) throw invalid_argument("inconsistent size"); });
384 
385  invalidate_sorting_flag();
386  reserve(n_elem + 1);
387  row_idx[n_elem] = row;
388  col_idx[n_elem] = col;
389  return val_idx[access::rw(n_elem)++] = data_t(0);
390 }
391 
392 template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::print() const {
393  suanpan_info("A sparse matrix in triplet form with size of %u by %u, the density of %.3f%%.\n", static_cast<unsigned>(n_rows), static_cast<unsigned>(n_cols), static_cast<double>(n_elem) / static_cast<double>(n_rows) / static_cast<double>(n_cols) * 1E2);
394  if(n_elem > index_t(1000)) {
395  suanpan_info("Not going to print all elements as more than 1000 elements exist.\n");
396  return;
397  }
398  for(index_t I = 0; I < n_elem; ++I) suanpan_info("(%3u, %3u) ===> %+.10E\n", static_cast<unsigned>(row_idx[I]), static_cast<unsigned>(col_idx[I]), val_idx[I]);
399 }
400 
401 template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::csr_sort() {
402  if(csr_sorted) return;
403 
404  std::vector<index_t> index(n_elem);
405  std::iota(index.begin(), index.end(), index_t(0));
406 
407  suanpan_sort(index.begin(), index.end(), csr_comparator<index_t>(row_idx.get(), col_idx.get()));
408 
409  index_ptr new_row_idx(new index_t[n_alloc]);
410  index_ptr new_col_idx(new index_t[n_alloc]);
411  data_ptr new_val_idx(new data_t[n_alloc]);
412 
413  suanpan_for(index_t(0), n_elem, [&](const index_t I) {
414  new_row_idx[I] = row_idx[index[I]];
415  new_col_idx[I] = col_idx[index[I]];
416  new_val_idx[I] = val_idx[index[I]];
417  });
418 
419  row_idx = std::move(new_row_idx);
420  col_idx = std::move(new_col_idx);
421  val_idx = std::move(new_val_idx);
422 
423  csr_sorted = true;
424  csc_sorted = false;
425 }
426 
427 template<sp_d data_t, sp_i index_t> void triplet_form<data_t, index_t>::csc_sort() {
428  if(csc_sorted) return;
429 
430  std::vector<index_t> index(n_elem);
431  std::iota(index.begin(), index.end(), index_t(0));
432 
433  suanpan_sort(index.begin(), index.end(), csc_comparator<index_t>(row_idx.get(), col_idx.get()));
434 
435  index_ptr new_row_idx(new index_t[n_alloc]);
436  index_ptr new_col_idx(new index_t[n_alloc]);
437  data_ptr new_val_idx(new data_t[n_alloc]);
438 
439  suanpan_for(index_t(0), n_elem, [&](const index_t I) {
440  new_row_idx[I] = row_idx[index[I]];
441  new_col_idx[I] = col_idx[index[I]];
442  new_val_idx[I] = val_idx[index[I]];
443  });
444 
445  row_idx = std::move(new_row_idx);
446  col_idx = std::move(new_col_idx);
447  val_idx = std::move(new_val_idx);
448 
449  csc_sorted = true;
450  csr_sorted = false;
451 }
452 
453 template<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) {
454  if(in_mat.empty()) return;
455 
456  invalidate_sorting_flag();
457 
458  const auto t_elem = n_elem + index_t(in_mat.n_elem);
459 
460  reserve(t_elem);
461 
462  suanpan_for(static_cast<uword>(0), in_mat.n_elem, [&](const uword I) {
463  row_idx[n_elem + I] = index_t(in_dof(I % in_dof.n_elem));
464  col_idx[n_elem + I] = index_t(in_dof(I / in_dof.n_elem));
465  val_idx[n_elem + I] = in_mat(I);
466  });
467 
468  access::rw(n_elem) = t_elem;
469 }
470 
471 template<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) {
472  if(in_mat.is_empty()) return;
473 
474  invalidate_sorting_flag();
475 
476  const auto t_elem = n_elem + in_mat.n_elem;
477 
478  reserve(t_elem);
479 
480  in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, row_shift, col_shift, scalar);
481 
482  access::rw(n_elem) = t_elem;
483 }
484 
485 template<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 {
487 
488  triplet_form<data_t, index_t> copy = *this;
489 
490  if(suanpan::approx_equal(T2(1), scalar)) return copy;
491 
492  if(suanpan::approx_equal(T2(-1), scalar))
493  suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [](data_t& I) { I = -I; });
494  else
495  suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [=](data_t& I) { I *= data_t(scalar); });
496 
497  return copy;
498 }
499 
500 template<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 {
501  triplet_form<data_t, index_t> copy = *this;
502 
503  if(suanpan::approx_equal(T2(1), scalar)) return copy;
504 
505  if(suanpan::approx_equal(T2(-1), scalar))
506  suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [](data_t& I) { I = -I; });
507  else
508  suanpan_for_each(copy.val_idx.get(), copy.val_idx.get() + copy.n_elem, [=](data_t& I) { I /= data_t(scalar); });
509 
510  return copy;
511 }
512 
513 template<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) {
514  if(suanpan::approx_equal(T2(1), scalar)) return *this;
515 
516  if(suanpan::approx_equal(T2(0), scalar)) zeros();
517  else if(suanpan::approx_equal(T2(-1), scalar))
518  suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [](data_t& I) { I = -I; });
519  else
520  suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [=](data_t& I) { I *= data_t(scalar); });
521 
522  return *this;
523 }
524 
525 template<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) {
526  if(suanpan::approx_equal(T2(1), scalar)) return *this;
527 
528  if(suanpan::approx_equal(T2(-1), scalar))
529  suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [](data_t& I) { I = -I; });
530  else
531  suanpan_for_each(val_idx.get(), val_idx.get() + n_elem, [=](data_t& I) { I /= data_t(scalar); });
532 
533  return *this;
534 }
535 
537  if(in_mat.is_empty()) return *this;
538 
539  invalidate_sorting_flag();
540 
541  const auto t_elem = n_elem + index_t(in_mat.n_elem);
542 
543  reserve(t_elem);
544 
545  in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, 0, 0, 1);
546 
547  access::rw(n_elem) = t_elem;
548 
549  return *this;
550 }
551 
553  if(in_mat.is_empty()) return *this;
554 
555  invalidate_sorting_flag();
556 
557  const auto t_elem = n_elem + index_t(in_mat.n_elem);
558 
559  reserve(t_elem);
560 
561  in_mat.copy_to(row_idx, col_idx, val_idx, n_elem, 0, 0, -1);
562 
563  access::rw(n_elem) = t_elem;
564 
565  return *this;
566 }
567 
568 template<sp_d data_t, sp_i index_t> Col<data_t> triplet_form<data_t, index_t>::diag() const {
569  Col<data_t> diag_vec(std::min(n_rows, n_cols), fill::zeros);
570  for(index_t I = 0; I < n_elem; ++I) if(row(I) == col(I)) diag_vec(row(I)) += val(I);
571  return diag_vec;
572 }
573 
574 template<sp_d data_t, sp_i index_t> triplet_form<data_t, index_t> triplet_form<data_t, index_t>::diagonal() const {
575  auto out_mat = *this;
576 
577  suanpan_for(index_t(0), out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.row(I) == out_mat.col(I); });
578 
579  return out_mat;
580 }
581 
583  auto out_mat = *this;
584 
585  suanpan_for(index_t(0), out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.row(I) < out_mat.col(I); });
586 
587  return out_mat;
588 }
589 
591  auto out_mat = *this;
592 
593  suanpan_for(index_t(0), out_mat.n_elem, [&](const index_t I) { out_mat.val_idx[I] *= out_mat.col(I) < out_mat.row(I); });
594 
595  return out_mat;
596 }
597 
598 template<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) {
599  auto out = mat_a;
600  out += mat_b;
601  return out;
602 }
603 
605  mat_a += mat_b;
606  return std::forward<triplet_form<data_t, index_t>>(mat_a);
607 }
608 
610  mat_b += mat_a;
611  return std::forward<triplet_form<data_t, index_t>>(mat_b);
612 }
613 
615  mat_a += mat_b;
616  return std::forward<triplet_form<data_t, index_t>>(mat_a);
617 }
618 
619 #endif
Storage< T >::iterator begin(Storage< T > &S)
Definition: Storage.hpp:200
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
triplet_form< data_t, index_t > & operator/=(T2)
Definition: triplet_form.hpp:525
void csr_sort()
Definition: triplet_form.hpp:401
data_t * val_mem()
Definition: triplet_form.hpp:157
triplet_form< data_t, index_t > strictly_lower() const
Definition: triplet_form.hpp:590
void zeros()
Definition: triplet_form.hpp:176
void assemble(const triplet_form< in_dt, in_it > &, index_t, index_t, data_t)
Definition: triplet_form.hpp:471
triplet_form()=default
Mat< data_t > operator*(const Col< data_t > &in_mat) const
Definition: triplet_form.hpp:237
const data_t * val_mem() const
Definition: triplet_form.hpp:151
index_t * row_mem()
Definition: triplet_form.hpp:153
const index_t n_rows
Definition: triplet_form.hpp:128
triplet_form< data_t, index_t > operator+(const triplet_form< data_t, index_t > &in_mat) const
Definition: triplet_form.hpp:258
const index_t * row_mem() const
Definition: triplet_form.hpp:147
const index_t n_alloc
Definition: triplet_form.hpp:131
data_t max() const
Definition: triplet_form.hpp:171
triplet_form< data_t, index_t > & operator+=(const triplet_form< data_t, index_t > &)
Definition: triplet_form.hpp:536
void csc_condense()
Definition: triplet_form.hpp:209
void csc_sort()
Definition: triplet_form.hpp:427
triplet_form< data_t, index_t > strictly_upper() const
Definition: triplet_form.hpp:582
triplet_form(triplet_form &&) noexcept
Definition: triplet_form.hpp:318
triplet_form< data_t, index_t > diagonal() const
Definition: triplet_form.hpp:574
const index_t * col_mem() const
Definition: triplet_form.hpp:149
bool is_empty() const
Definition: triplet_form.hpp:169
data_t & at(index_t, index_t)
Definition: triplet_form.hpp:382
void full_csr_condense()
Definition: triplet_form.hpp:214
void csr_condense()
Definition: triplet_form.hpp:204
bool is_csc_sorted() const
Definition: triplet_form.hpp:167
index_t * col_mem()
Definition: triplet_form.hpp:155
triplet_form(const SpMat< in_dt > &)
Definition: triplet_form.hpp:355
triplet_form(const triplet_form &)
Definition: triplet_form.hpp:308
data_t data_type
Definition: triplet_form.hpp:121
triplet_form & operator=(const triplet_form &)
Definition: triplet_form.hpp:329
triplet_form< data_t, index_t > operator*(T2) const
Definition: triplet_form.hpp:485
const index_t n_cols
Definition: triplet_form.hpp:129
triplet_form< data_t, index_t > & operator*=(T2)
Definition: triplet_form.hpp:513
Mat< data_t > operator*(const Mat< data_t > &in_mat) const
Definition: triplet_form.hpp:245
void init(const index_t in_rows, const index_t in_cols, const index_t in_elem)
Definition: triplet_form.hpp:186
const index_t n_elem
Definition: triplet_form.hpp:130
void init(const index_t in_elem)
Definition: triplet_form.hpp:181
void print() const
Definition: triplet_form.hpp:392
Col< data_t > diag() const
Definition: triplet_form.hpp:568
friend class triplet_form
Definition: triplet_form.hpp:126
bool is_csr_sorted() const
Definition: triplet_form.hpp:165
index_t index_type
Definition: triplet_form.hpp:122
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:229
index_t col(const index_t I) const
Definition: triplet_form.hpp:161
data_t val(const index_t I) const
Definition: triplet_form.hpp:163
void assemble(const Mat< data_t > &, const Col< uword > &)
Definition: triplet_form.hpp:453
index_t row(const index_t I) const
Definition: triplet_form.hpp:159
triplet_form< data_t, index_t > & operator-=(const triplet_form< data_t, index_t > &)
Definition: triplet_form.hpp:552
void full_csc_condense()
Definition: triplet_form.hpp:220
triplet_form(triplet_form< in_dt, in_it > &, SparseBase=SparseBase::ZERO, bool=false)
Definition: triplet_form.hpp:363
const data_t & operator()(const index_t row, const index_t col) const
Definition: triplet_form.hpp:192
triplet_form< data_t, index_t > operator-(const triplet_form< data_t, index_t > &in_mat) const
Definition: triplet_form.hpp:263
triplet_form< data_t, index_t > operator/(T2) const
Definition: triplet_form.hpp:500
std::enable_if_t<!std::numeric_limits< T >::is_integer, bool > approx_equal(T x, T y, int ulp=2)
Definition: utility.h:46
void suanpan_debug(const char *M,...)
Definition: print.cpp:64
void suanpan_info(const char *M,...)
Definition: print.cpp:47
concept sp_d
Definition: suanPan.h:227
#define suanpan_for_each
Definition: suanPan.h:176
#define suanpan_sort
Definition: suanPan.h:175
concept sp_i
Definition: suanPan.h:228
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:598
SparseBase
Definition: triplet_form.hpp:27
void suanpan_for(const IT start, const IT end, F &&FN)
Definition: utility.h:24