Expression Templates Library (ETL)
sparse.hpp
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
8 #pragma once
9 
10 #include "etl/dyn_base.hpp" //The base class and utilities
11 
12 namespace etl {
13 
14 namespace sparse_detail {
15 
20 template <typename M>
22  using matrix_type = M;
26  using const_raw_reference_type = std::add_const_t<value_type>&;
27 
29  size_t i;
30  size_t j;
31  size_t n;
33 
40  sparse_reference(matrix_type& matrix, size_t i, size_t j) : matrix(matrix), i(i), j(j) {
41  n = matrix.find_n(i, j);
42  matrix.unsafe_set_hint(i, j, n, matrix.get_hint(i, j, n));
43  ptr = &matrix.unsafe_ref_hint(n);
44  }
45 
50  //Update the value, possibly erasing it
51  matrix.set_hint(i, j, n, *ptr);
52  }
53 
55  sparse_reference& operator=(sparse_reference&) = delete;
56 
58  sparse_reference& operator=(sparse_reference&&) = delete;
59 
66  get() = rhs;
67  return *this;
68  }
69 
76  get() += rhs;
77  return *this;
78  }
79 
86  get() -= rhs;
87  return *this;
88  }
89 
96  get() *= rhs;
97  return *this;
98  }
99 
106  get() /= rhs;
107  return *this;
108  }
109 
116  get() %= rhs;
117  return *this;
118  }
119 
124  operator raw_reference_type() {
125  return get();
126  }
127 
132  operator const_raw_reference_type() const {
133  return get();
134  }
135 
136 private:
137  raw_reference_type get() {
138  return *ptr;
139  }
140 
141  const_raw_reference_type get() const {
142  return *ptr;
143  }
144 };
145 
152 inline bool is_zero(double a) {
153  return a == 0.0;
154 }
155 
159 inline bool is_zero(float a) {
160  return a == 0.0f;
161 }
162 
166 inline bool is_zero(std::complex<float> a) {
167  return a.real() == 0.0f && a.imag() == 0.0f;
168 }
169 
173 inline bool is_zero(std::complex<double> a) {
174  return a.real() == 0.0 && a.imag() == 0.0;
175 }
176 
180 inline bool is_zero(etl::complex<float> a) {
181  return a.real == 0.0f && a.imag == 0.0f;
182 }
183 
187 inline bool is_zero(etl::complex<double> a) {
188  return a.real == 0.0 && a.imag == 0.0;
189 }
190 
197 template <typename T>
198 bool is_non_zero(T value) {
199  return !is_zero(value);
200 }
201 
202 } //end of namespace sparse_detail
203 
210 template <typename T, sparse_storage SS, size_t D>
212 
218 template <typename T, size_t D>
219 requires(D == 2)
220 struct sparse_matrix_impl<T, sparse_storage::COO, D> final : dyn_base<sparse_matrix_impl<T, sparse_storage::COO, D>, T, D> {
221  static constexpr size_t n_dimensions = D;
222  static constexpr sparse_storage storage_format = sparse_storage::COO;
223  static constexpr order storage_order = order::RowMajor;
224  static constexpr size_t alignment = default_intrinsic_traits<T>::alignment;
225 
227  using base_type = dyn_base<this_type, T, D>;
230  using value_type = T;
231  using dimension_storage_impl = std::array<size_t, n_dimensions>;
232  using memory_type = value_type*;
233  using const_memory_type = const value_type*;
234  using index_type = size_t;
236 
238  friend struct sparse_detail::sparse_reference<const this_type>;
239 
240 private:
241  using base_type::_dimensions;
242  using base_type::_size;
243  memory_type _memory;
244  index_memory_type _row_index;
245  index_memory_type _col_index;
246  size_t nnz;
247 
248  using base_type::allocate;
249  using base_type::check_invariants;
250  using base_type::release;
251 
256  template <typename It>
257  void build_from_iterable(const It& iterable) {
258  nnz = 0;
259  for (auto v : iterable) {
260  if (sparse_detail::is_non_zero(v)) {
261  ++nnz;
262  }
263  }
264 
265  if (nnz > 0) {
266  //Allocate space for the three arrays
267  _memory = allocate(nnz);
268  _row_index = base_type::template allocate<index_type>(nnz);
269  _col_index = base_type::template allocate<index_type>(nnz);
270 
271  auto it = iterable.begin();
272  size_t n = 0;
273 
274  for (size_t i = 0; i < rows(); ++i) {
275  for (size_t j = 0; j < columns(); ++j) {
276  if (sparse_detail::is_non_zero(*it)) {
277  _memory[n] = *it;
278  _row_index[n] = i;
279  _col_index[n] = j;
280  ++n;
281  }
282 
283  ++it;
284  }
285  }
286  }
287  }
288 
292  void reserve_hint(size_t hint) {
293  cpp_assert(hint < nnz + 1, "Invalid hint for reserve_hint");
294 
295  if (_memory) {
296  auto new_memory = allocate(nnz + 1);
297  auto new_row_index = base_type::template allocate<index_type>(nnz + 1);
298  auto new_col_index = base_type::template allocate<index_type>(nnz + 1);
299 
300  if (hint == nnz) {
301  //Copy the elements
302  std::copy_n(_memory, nnz, new_memory);
303  std::copy_n(_row_index, nnz, new_row_index);
304  std::copy_n(_col_index, nnz, new_col_index);
305  } else {
306  //Copy the elements before hint
307  std::copy(_memory, _memory + hint, new_memory);
308  std::copy(_row_index, _row_index + hint, new_row_index);
309  std::copy(_col_index, _col_index + hint, new_col_index);
310 
311  //Copy the elements after hint
312  std::copy(_memory + hint, _memory + nnz, new_memory + hint + 1);
313  std::copy(_row_index + hint, _row_index + nnz, new_row_index + hint + 1);
314  std::copy(_col_index + hint, _col_index + nnz, new_col_index + hint + 1);
315  }
316 
317  release(_memory, nnz);
318  release(_row_index, nnz);
319  release(_col_index, nnz);
320 
321  _memory = new_memory;
322  _col_index = new_col_index;
323  _row_index = new_row_index;
324  } else {
325  cpp_assert(hint == 0, "Invalid hint for reserve_hint");
326 
327  _memory = allocate(nnz + 1);
328  _row_index = base_type::template allocate<index_type>(nnz + 1);
329  _col_index = base_type::template allocate<index_type>(nnz + 1);
330  }
331 
332  ++nnz;
333  }
334 
338  void erase_hint(size_t n) {
339  cpp_assert(nnz > 0, "Invalid erase_hint call (no non-zero elements");
340 
341  if (nnz == 1) {
342  release(_memory, nnz);
343  release(_row_index, nnz);
344  release(_col_index, nnz);
345 
346  _memory = nullptr;
347  _row_index = nullptr;
348  _col_index = nullptr;
349  } else {
350  auto new_memory = allocate(nnz - 1);
351  auto new_row_index = base_type::template allocate<index_type>(nnz - 1);
352  auto new_col_index = base_type::template allocate<index_type>(nnz - 1);
353 
354  if (n == nnz - 1) {
355  std::copy_n(_memory, nnz - 1, new_memory);
356  std::copy_n(_row_index, nnz - 1, new_row_index);
357  std::copy_n(_col_index, nnz - 1, new_col_index);
358  } else {
359  std::copy(_memory, _memory + n, new_memory);
360  std::copy(_row_index, _row_index + n, new_row_index);
361  std::copy(_col_index, _col_index + n, new_col_index);
362 
363  std::copy(_memory + n + 1, _memory + nnz, new_memory + n);
364  std::copy(_row_index + n + 1, _row_index + nnz, new_row_index + n);
365  std::copy(_col_index + n + 1, _col_index + nnz, new_col_index + n);
366  }
367 
368  release(_memory, nnz);
369  release(_row_index, nnz);
370  release(_col_index, nnz);
371 
372  _memory = new_memory;
373  _row_index = new_row_index;
374  _col_index = new_col_index;
375  }
376 
377  --nnz;
378  }
379 
385  size_t find_n(size_t i, size_t j) const noexcept {
386  for (size_t n = 0; n < nnz; ++n) {
387  //The value exists, modify it
388  if (_row_index[n] == i && _col_index[n] == j) {
389  return n;
390  }
391 
392  //The insertion point has been found
393  if ((_row_index[n] == i && _col_index[n] > j) || _row_index[n] > i) {
394  return n;
395  }
396  }
397 
398  return nnz;
399  }
400 
405  void unsafe_set_hint(size_t i, size_t j, size_t n, value_type value) {
406  //The value exists, modify it
407  if (n < nnz && _row_index[n] == i && _col_index[n] == j) {
408  _memory[n] = value;
409  return;
410  }
411 
412  reserve_hint(n);
413 
414  _memory[n] = value;
415  _row_index[n] = i;
416  _col_index[n] = j;
417  }
418 
422  value_type get_hint(size_t i, size_t j, size_t n) const noexcept requires(n_dimensions == 2) {
423  if (n < nnz && _row_index[n] == i && _col_index[n] == j) {
424  return _memory[n];
425  }
426 
427  return 0.0;
428  }
429 
433  void set_hint(size_t i, size_t j, size_t n, value_type value) {
434  if (n < nnz) {
435  if (_row_index[n] == i && _col_index[n] == j) {
436  //At this point, there is already a value for (i,j)
437  //If zero, we remove it, otherwise edit it
438  if (sparse_detail::is_non_zero(value)) {
439  unsafe_set_hint(i, j, n, value);
440  } else {
441  erase_hint(n);
442  }
443  } else {
444  //At this point, the value does not exist
445  //We insert it if not zero
446  if (sparse_detail::is_non_zero(value)) {
447  unsafe_set_hint(i, j, n, value);
448  }
449  }
450  } else {
451  //At this point, the value does not exist
452  //We insert it if not zero
453  if (sparse_detail::is_non_zero(value)) {
454  unsafe_set_hint(i, j, n, value);
455  }
456  }
457  }
458 
462  value_type& unsafe_ref_hint(size_t n) {
463  return _memory[n];
464  }
465 
469  const value_type& unsafe_ref_hint(size_t n) const {
470  return _memory[n];
471  }
472 
478  template <not_generator E>
479  void inherit(const E& e) {
480  cpp_assert(n_dimensions == etl::dimensions(e), "Invalid number of dimensions");
481 
482  // Compute the size and new dimensions
483  _size = 1;
484  for (size_t d = 0; d < n_dimensions; ++d) {
485  _dimensions[d] = etl::dim(e, d);
486  _size *= _dimensions[d];
487  }
488  }
489 
490 public:
491  using base_type::columns;
492  using base_type::dim;
493  using base_type::rows;
494  using base_type::size;
495 
496  // Construction
497 
501  sparse_matrix_impl() noexcept : base_type(), _memory(nullptr), _row_index(nullptr), _col_index(nullptr), nnz(0) {
502  //Nothing else to init
503  }
504 
509  template <size_c... S>
510  explicit sparse_matrix_impl(S... sizes) noexcept requires(sizeof...(S) == D)
511  : base_type(util::size(sizes...), {{static_cast<size_t>(sizes)...}}), _memory(nullptr), _row_index(nullptr), _col_index(nullptr), nnz(0) {
512  //Nothing else to init
513  }
514 
519  template <typename... S>
520  explicit sparse_matrix_impl(S... sizes) noexcept requires(dyn_detail::is_initializer_list_constructor<S...>::value && sizeof...(S) == D + 1)
521  : base_type(util::size(std::make_index_sequence<(sizeof...(S) - 1)>(), sizes...),
522  dyn_detail::sizes(std::make_index_sequence<(sizeof...(S) - 1)>(), sizes...)) {
523  static_assert(sizeof...(S) == D + 1, "Invalid number of dimensions");
524 
525  auto list = cpp::last_value(sizes...);
526  build_from_iterable(list);
527  }
528 
533  template <typename S1, typename... S>
534  explicit sparse_matrix_impl(S1 s1, S... sizes) noexcept requires((sizeof...(S) == D) && cpp::specialization_of<values_t, typename cpp::last_type<S1, S...>::type>)
535  : base_type(util::size(std::make_index_sequence<(sizeof...(S))>(), s1, sizes...),
536  dyn_detail::sizes(std::make_index_sequence<(sizeof...(S))>(), s1, sizes...)) {
537  auto list = cpp::last_value(sizes...).template list<value_type>();
538  build_from_iterable(list);
539  }
540 
549  sparse_matrix_impl& operator=(const sparse_matrix_impl& rhs) noexcept {
550  if (this != &rhs) {
551  if (!_size) {
552  inherit(rhs);
553  } else {
554  validate_assign(*this, rhs);
555  }
556 
557  // Note: The const_cast is necessary in order to call assign_to
558  // and the parameter cannot be made non-const
559  const_cast<sparse_matrix_impl&>(rhs).assign_to(*this);
560  }
561 
562  check_invariants();
563 
564  return *this;
565  }
566 
570  template <etl_expr E>
571  sparse_matrix_impl& operator=(E&& e) noexcept
572  requires(!std::same_as<std::decay_t<E>, sparse_matrix_impl<T, storage_format, D>> && std::convertible_to<value_t<E>, value_type>) {
573  // It is possible that the matrix was not initialized before
574  // In the case, get the the dimensions from the expression and
575  // initialize the matrix
576  if (!_size) {
577  inherit(e);
578  } else {
579  validate_assign(*this, e);
580  }
581 
582  // Avoid aliasing issues
583  if constexpr (!decay_traits<E>::is_linear) {
584  if (e.alias(*this)) {
585  // Create a temporary to hold the result
586  this_type tmp(*this);
587 
588  // Assign the expression to the temporary
589  tmp = e;
590 
591  // Assign the temporary to this matrix
592  *this = tmp;
593  } else {
594  e.assign_to(*this);
595  }
596  } else {
597  // Direct assignment of the expression into this matrix
598  e.assign_to(*this);
599  }
600 
601  check_invariants();
602 
603  return *this;
604  }
605 
617  value_type get(size_t i, size_t j) const noexcept(assert_nothrow) {
618  cpp_assert(i < dim(0), "Out of bounds");
619  cpp_assert(j < dim(1), "Out of bounds");
620 
621  auto n = find_n(i, j);
622  return get_hint(i, j, n);
623  }
624 
631  reference_type operator()(size_t i, size_t j) noexcept(assert_nothrow) {
632  cpp_assert(i < dim(0), "Out of bounds");
633  cpp_assert(j < dim(1), "Out of bounds");
634 
635  return {*this, i, j};
636  }
637 
644  const_reference_type operator()(size_t i, size_t j) const noexcept(assert_nothrow) {
645  cpp_assert(i < dim(0), "Out of bounds");
646  cpp_assert(j < dim(1), "Out of bounds");
647 
648  return {*this, i, j};
649  }
650 
658  reference_type operator[](size_t n) noexcept(assert_nothrow) {
659  cpp_assert(n < size(), "Out of bounds");
660 
661  return {*this, n / columns(), n % columns()};
662  }
663 
671  const_reference_type operator[](size_t n) const noexcept(assert_nothrow) {
672  cpp_assert(n < size(), "Out of bounds");
673 
674  return {*this, n / columns(), n % columns()};
675  }
676 
683  value_type read_flat(size_t n) const noexcept requires(n_dimensions == 2) {
684  return get(n / columns(), n % columns());
685  }
686 
694  size_t non_zeros() const noexcept {
695  return nnz;
696  }
697 
704  void set(size_t i, size_t j, value_type value) {
705  cpp_assert(i < dim(0), "Out of bounds");
706  cpp_assert(j < dim(1), "Out of bounds");
707 
708  auto n = find_n(i, j);
709  set_hint(i, j, n, value);
710  }
711 
723  void unsafe_set(size_t i, size_t j, value_type value) {
724  cpp_assert(i < dim(0), "Out of bounds");
725  cpp_assert(j < dim(1), "Out of bounds");
726 
727  auto n = find_n(i, j);
728 
729  unsafe_set_hint(i, j, n, value);
730  }
731 
737  void erase(size_t i, size_t j) {
738  cpp_assert(i < dim(0), "Out of bounds");
739  cpp_assert(j < dim(1), "Out of bounds");
740 
741  auto n = find_n(i, j);
742 
743  if (n < nnz && _row_index[n] == i && _col_index[n] == j) {
744  erase_hint(n);
745  }
746  }
747 
753  template <typename E>
754  bool alias(const E& rhs) const noexcept {
755  if constexpr (is_sparse_matrix<E>) {
756  return this == &rhs;
757  } else {
758  return rhs.alias(*this);
759  }
760  }
761 
762  // Internals
763 
768  template <typename V>
769  void visit([[maybe_unused]] V&& visitor) const {}
770 
774  ~sparse_matrix_impl() noexcept {
775  if (_memory) {
776  release(_memory, nnz);
777  release(_row_index, nnz);
778  release(_col_index, nnz);
779  }
780  }
781 
786  void ensure_cpu_up_to_date() const {
787  // No GPU support for sparse matrix so far
788  }
789 
794  void ensure_gpu_up_to_date() const {
795  // No GPU support for sparse matrix so far
796  }
797 
802  template <typename L>
803  void assign_to(L&& lhs) const {
804  std_assign_evaluate(*this, std::forward<L>(lhs));
805  }
806 
811  template <typename L>
812  void assign_add_to(L&& lhs) const {
813  std_add_evaluate(*this, std::forward<L>(lhs));
814  }
815 
820  template <typename L>
821  void assign_sub_to(L&& lhs) const {
822  std_sub_evaluate(*this, std::forward<L>(lhs));
823  }
824 
829  template <typename L>
830  void assign_mul_to(L&& lhs) const {
831  std_mul_evaluate(*this, std::forward<L>(lhs));
832  }
833 
838  template <typename L>
839  void assign_div_to(L&& lhs) const {
840  std_div_evaluate(*this, std::forward<L>(lhs));
841  }
842 
847  template <typename L>
848  void assign_mod_to(L&& lhs) const {
849  std_mod_evaluate(*this, std::forward<L>(lhs));
850  }
851 
858  friend std::ostream& operator<<(std::ostream& os, const sparse_matrix_impl& matrix) {
859  os << "SM[" << matrix.dim(0);
860 
861  for (size_t i = 1; i < D; ++i) {
862  os << "," << matrix.dim(i);
863  }
864 
865  return os << "]";
866  }
867 };
868 
869 } //end of namespace etl
Simple collection of values to initialize a dyn matrix.
Definition: dyn_base.hpp:36
CRTP class to inject iterators functions.
Definition: iterable.hpp:23
void assign_add_to(L &&lhs) const
Add to the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:217
sparse_reference & operator*=(value_type rhs)
Multiply by a new value the proxy reference.
Definition: sparse.hpp:95
Complex number implementation.
Definition: complex.hpp:31
sparse_reference & operator=(value_type rhs)
Sets a new value to the proxy reference.
Definition: sparse.hpp:65
void std_assign_evaluate(Expr &&expr, Result &&result)
Evaluation of the expr into result.
Definition: evaluator.hpp:1176
bool alias(const E &rhs) const noexcept
Test if this expression aliases with the given expression.
Definition: dyn_matrix_view.hpp:197
void assign_div_to(L &&lhs) const
Divide the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:244
value_type * raw_pointer_type
A raw pointer type.
Definition: sparse.hpp:24
value_t< sub_type > value_type
The value contained in the expression.
Definition: dyn_matrix_view.hpp:31
void assign_mul_to(L &&lhs) const
Multiply the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:235
size_t n
hint
Definition: sparse.hpp:31
const_memory_t< sub_type > const_memory_type
The const memory access type.
Definition: dyn_matrix_view.hpp:33
value_type & raw_reference_type
A raw reference type.
Definition: sparse.hpp:25
void assign_to(L &&lhs) const
Assign to the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:208
D D
The number of dimensions.
Definition: dyn_matrix_view.hpp:24
Define traits to get vectorization information for types when no vector mode is available.
Definition: no_vectorization.hpp:16
order
Storage order of a matrix.
Definition: order.hpp:15
index_type * index_memory_type
The memory type to the COO index.
Definition: sparse.hpp:235
raw_pointer_type ptr
Pointer to the element.
Definition: sparse.hpp:32
memory_t< sub_type > memory_type
The memory acess type.
Definition: dyn_matrix_view.hpp:32
dyn_base< this_type, T, D > base_type
The base type.
Definition: sparse.hpp:227
Traits to get information about ETL types.
Definition: tmp.hpp:68
Root namespace for the ETL library.
Definition: adapter.hpp:15
auto dim(E &&value, size_t i) -> detail::identity_helper< E, dim_view< detail::build_identity_type< E >, D >>
Return a view representing the ith Dth dimension.
Definition: view_expression_builder.hpp:25
Coordinate Format (COO)
Definition: sparse.hpp:220
M matrix_type
The matrix type.
Definition: sparse.hpp:22
std::ostream & operator<<(std::ostream &os, const etl::complex< T > &c)
Outputs a textual representation of the complex number in the given stream.
Definition: complex.hpp:576
size_t columns(const E &expr)
Returns the number of columns of the given ETL expression.
Definition: helpers.hpp:78
void ensure_cpu_up_to_date() const
Ensures that the GPU memory is allocated and that the GPU memory is up to date (to undefined value)...
Definition: dyn_matrix_view.hpp:271
sparse_storage
Enumeration for sparse storage formats.
Definition: sparse_storage.hpp:20
typename matrix_type::value_type value_type
The value type.
Definition: sparse.hpp:23
void std_mod_evaluate(Expr &&expr, Result &&result)
Compound modulo evaluation of the expr into result.
Definition: evaluator.hpp:1271
const_return_type operator()(size_t j) const
Access to the element at the given position.
Definition: dyn_matrix_view.hpp:89
matrix_type & matrix
Reference to the matrix.
Definition: sparse.hpp:28
value_type read_flat(size_t j) const noexcept
Returns the value at the given index This function never has side effects.
Definition: dyn_matrix_view.hpp:111
void std_mul_evaluate(Expr &&expr, Result &&result)
Compound multiply evaluation of the expr into result.
Definition: evaluator.hpp:1233
Base class and utilities for dyn matrix implementations.
void visit(detail::evaluator_visitor &visitor) const
Apply the given visitor to this expression and its descendants.
Definition: dyn_matrix_view.hpp:263
requires(D > 0) struct dyn_base
Matrix with run-time fixed dimensions.
Definition: dyn_base.hpp:113
sparse_reference & operator-=(value_type rhs)
Subtract a new value from the proxy reference.
Definition: sparse.hpp:85
void ensure_gpu_up_to_date() const
Copy back from the GPU to the expression memory if necessary.
Definition: dyn_matrix_view.hpp:280
Definition: expr_fwd.hpp:59
sparse_reference & operator%=(value_type rhs)
Modulo by a new value the proxy reference.
Definition: sparse.hpp:115
value_type real
The real part.
Definition: complex.hpp:34
void std_sub_evaluate(Expr &&expr, Result &&result)
Compound subtract evaluation of the expr into result.
Definition: evaluator.hpp:1214
std::array< size_t, n_dimensions > dimension_storage_impl
The type used to store the dimensions.
Definition: sparse.hpp:231
void assign_mod_to(L &&lhs) const
Modulo the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:253
sparse_reference & operator/=(value_type rhs)
Divide by a new value the proxy reference.
Definition: sparse.hpp:105
size_t index_type
The type used to store the COO index.
Definition: sparse.hpp:234
const_return_type operator[](size_t j) const
Returns the element at the given index.
Definition: dyn_matrix_view.hpp:71
sparse_reference & operator+=(value_type rhs)
Adds a new value to the proxy reference.
Definition: sparse.hpp:75
auto allocate(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate an array of the given size for the given type.
Definition: allocator.hpp:80
Traits to test if the constructor is an initializer list constructor.
Definition: dyn_base.hpp:89
size_t j
The second index.
Definition: sparse.hpp:30
size_t rows(const E &expr)
Returns the number of rows of the given ETL expression.
Definition: helpers.hpp:58
value_type imag
The imaginary part.
Definition: complex.hpp:35
Sparse matrix implementation.
Definition: sparse.hpp:211
typename decay_traits< E >::value_type value_t
Traits to extract the value type out of an ETL type.
Definition: tmp.hpp:81
size_t i
The first index.
Definition: sparse.hpp:29
void std_div_evaluate(Expr &&expr, Result &&result)
Compound divide evaluation of the expr into result.
Definition: evaluator.hpp:1252
Row-Major storage.
sparse_reference(matrix_type &matrix, size_t i, size_t j)
Constructs a new sparse_reference.
Definition: sparse.hpp:40
~sparse_reference()
Destruct the proxy reference and updates the matrix to the correct value.
Definition: sparse.hpp:49
A proxy representing a reference to an element of a sparse matrix.
Definition: sparse.hpp:21
std::add_const_t< value_type > & const_raw_reference_type
A raw const reference type.
Definition: sparse.hpp:26
void std_add_evaluate(Expr &&expr, Result &&result)
Compound add evaluation of the expr into result.
Definition: evaluator.hpp:1195
void assign_sub_to(L &&lhs) const
Sub from the given left-hand-side expression.
Definition: dyn_matrix_view.hpp:226