Eigen  5.0.1
 
Loading...
Searching...
No Matches
SparseCompressedBase.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2015 Gael Guennebaud <gael.guennebaud@inria.fr>
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_SPARSE_COMPRESSED_BASE_H
12#define EIGEN_SPARSE_COMPRESSED_BASE_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17namespace Eigen {
18
19template <typename Derived>
21
22namespace internal {
23
24template <typename Derived>
25struct traits<SparseCompressedBase<Derived>> : traits<Derived> {};
26
27template <typename Derived, class Comp, bool IsVector>
28struct inner_sort_impl;
29
30} // end namespace internal
31
43template <typename Derived>
44class SparseCompressedBase : public SparseMatrixBase<Derived> {
45 public:
46 using Base = SparseMatrixBase<Derived>;
47 EIGEN_SPARSE_PUBLIC_INTERFACE(SparseCompressedBase)
48 using Base::operator=;
49 using Base::IsRowMajor;
50
51 class InnerIterator;
52 class ReverseInnerIterator;
53
54 protected:
55 using IndexVector = typename Base::IndexVector;
56 Eigen::Map<IndexVector> innerNonZeros() {
58 }
59 const Eigen::Map<const IndexVector> innerNonZeros() const {
61 }
62
63 public:
65 inline Index nonZeros() const {
66 if (Derived::IsVectorAtCompileTime && outerIndexPtr() == 0)
67 return derived().nonZeros();
68 else if (derived().outerSize() == 0)
69 return 0;
70 else if (isCompressed())
71 return outerIndexPtr()[derived().outerSize()] - outerIndexPtr()[0];
72 else
73 return innerNonZeros().sum();
74 }
75
79 inline const Scalar* valuePtr() const { return derived().valuePtr(); }
83 inline Scalar* valuePtr() { return derived().valuePtr(); }
84
88 inline const StorageIndex* innerIndexPtr() const { return derived().innerIndexPtr(); }
92 inline StorageIndex* innerIndexPtr() { return derived().innerIndexPtr(); }
93
98 inline const StorageIndex* outerIndexPtr() const { return derived().outerIndexPtr(); }
103 inline StorageIndex* outerIndexPtr() { return derived().outerIndexPtr(); }
104
108 inline const StorageIndex* innerNonZeroPtr() const { return derived().innerNonZeroPtr(); }
112 inline StorageIndex* innerNonZeroPtr() { return derived().innerNonZeroPtr(); }
113
115 inline bool isCompressed() const { return innerNonZeroPtr() == 0; }
116
117 protected:
118 Index coeffsStart() const {
119 const StorageIndex* outer = outerIndexPtr();
120 return (outer && derived().outerSize() > 0) ? internal::convert_index<Index>(outer[0]) : 0;
121 }
122
123 public:
130 eigen_assert(isCompressed());
131 const Index start = coeffsStart();
132 const Scalar* values = valuePtr() + start;
133 return Array<Scalar, Dynamic, 1>::Map(values, nonZeros());
134 }
135
147 eigen_assert(isCompressed());
148 const Index start = coeffsStart();
149 Scalar* values = valuePtr() + start;
150 return Array<Scalar, Dynamic, 1>::Map(values, nonZeros());
151 }
152
155 template <class Comp = std::less<>>
156 inline void sortInnerIndices(Index begin, Index end) {
157 eigen_assert(begin >= 0 && end <= derived().outerSize() && end >= begin);
158 internal::inner_sort_impl<Derived, Comp, IsVectorAtCompileTime>::run(*this, begin, end);
159 }
160
163 template <class Comp = std::less<>>
164 inline Index innerIndicesAreSorted(Index begin, Index end) const {
165 eigen_assert(begin >= 0 && end <= derived().outerSize() && end >= begin);
166 return internal::inner_sort_impl<Derived, Comp, IsVectorAtCompileTime>::check(*this, begin, end);
167 }
168
171 template <class Comp = std::less<>>
172 inline void sortInnerIndices() {
173 Index begin = 0;
174 Index end = derived().outerSize();
175 internal::inner_sort_impl<Derived, Comp, IsVectorAtCompileTime>::run(*this, begin, end);
176 }
177
180 template <class Comp = std::less<>>
182 Index begin = 0;
183 Index end = derived().outerSize();
184 return internal::inner_sort_impl<Derived, Comp, IsVectorAtCompileTime>::check(*this, begin, end);
185 }
186
187 protected:
190
194 internal::LowerBoundIndex lower_bound(Index row, Index col) const {
195 eigen_internal_assert(row >= 0 && row < this->rows() && col >= 0 && col < this->cols());
196
197 const Index outer = Derived::IsRowMajor ? row : col;
198 const Index inner = Derived::IsRowMajor ? col : row;
199
200 Index start = this->outerIndexPtr()[outer];
201 Index end = this->isCompressed() ? this->outerIndexPtr()[outer + 1]
202 : this->outerIndexPtr()[outer] + this->innerNonZeroPtr()[outer];
203 eigen_assert(end >= start && "you are using a non finalized sparse matrix or written coefficient does not exist");
204 internal::LowerBoundIndex p;
205 p.value =
206 std::lower_bound(this->innerIndexPtr() + start, this->innerIndexPtr() + end, inner) - this->innerIndexPtr();
207 p.found = (p.value < end) && (this->innerIndexPtr()[p.value] == inner);
208 return p;
209 }
210
211 friend struct internal::evaluator<SparseCompressedBase<Derived>>;
212
213 private:
214 template <typename OtherDerived>
216};
217
218template <typename Derived>
219class SparseCompressedBase<Derived>::InnerIterator {
220 public:
221 InnerIterator() = default;
222
223 InnerIterator(const InnerIterator& other)
224 : m_values(other.m_values),
225 m_indices(other.m_indices),
226 m_outer(other.m_outer),
227 m_id(other.m_id),
228 m_end(other.m_end) {}
229
230 InnerIterator& operator=(const InnerIterator& other) {
231 m_values = other.m_values;
232 m_indices = other.m_indices;
233 const_cast<OuterType&>(m_outer).setValue(other.m_outer.value());
234 m_id = other.m_id;
235 m_end = other.m_end;
236 return *this;
237 }
238
239 InnerIterator(const SparseCompressedBase& mat, Index outer)
240 : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer) {
241 if (Derived::IsVectorAtCompileTime && mat.outerIndexPtr() == 0) {
242 m_id = 0;
243 m_end = mat.nonZeros();
244 } else {
245 m_id = mat.outerIndexPtr()[outer];
246 if (mat.isCompressed())
247 m_end = mat.outerIndexPtr()[outer + 1];
248 else
249 m_end = m_id + mat.innerNonZeroPtr()[outer];
250 }
251 }
252
253 explicit InnerIterator(const SparseCompressedBase& mat) : InnerIterator(mat, Index(0)) {
254 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
255 }
256
257 explicit InnerIterator(const internal::CompressedStorage<Scalar, StorageIndex>& data)
258 : m_values(data.valuePtr()), m_indices(data.indexPtr()), m_outer(0), m_id(0), m_end(data.size()) {
259 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
260 }
261
262 inline InnerIterator& operator++() {
263 m_id++;
264 return *this;
265 }
266 inline InnerIterator& operator+=(Index i) {
267 m_id += i;
268 return *this;
269 }
270
271 inline InnerIterator operator+(Index i) {
272 InnerIterator result = *this;
273 result += i;
274 return result;
275 }
276
277 inline const Scalar& value() const { return m_values[m_id]; }
278 inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id]); }
279
280 inline StorageIndex index() const { return m_indices[m_id]; }
281 inline Index outer() const { return m_outer.value(); }
282 inline Index row() const { return IsRowMajor ? m_outer.value() : index(); }
283 inline Index col() const { return IsRowMajor ? index() : m_outer.value(); }
284
285 inline operator bool() const { return m_id < m_end; }
286
287 // Position-based equality (bug #1192 — without these, == falls back to bool conversion).
288 inline bool operator==(const InnerIterator& other) const {
289 eigen_assert(m_values == other.m_values && "comparing iterators from different sources");
290 return m_outer.value() == other.m_outer.value() && m_id == other.m_id;
291 }
292 inline bool operator!=(const InnerIterator& other) const { return !(*this == other); }
293
294 protected:
295 const Scalar* m_values = nullptr;
296 const StorageIndex* m_indices = nullptr;
297 using OuterType = internal::variable_if_dynamic<Index, Derived::IsVectorAtCompileTime ? 0 : Dynamic>;
298 const OuterType m_outer{0};
299 Index m_id = 0;
300 Index m_end = 0;
301
302 private:
303 // If you get here, then you're not using the right InnerIterator type, e.g.:
304 // SparseMatrix<double,RowMajor> A;
305 // SparseMatrix<double>::InnerIterator it(A,0);
306 template <typename T>
307 InnerIterator(const SparseMatrixBase<T>&, Index outer);
308};
309
310template <typename Derived>
311class SparseCompressedBase<Derived>::ReverseInnerIterator {
312 public:
313 ReverseInnerIterator(const SparseCompressedBase& mat, Index outer)
314 : m_values(mat.valuePtr()), m_indices(mat.innerIndexPtr()), m_outer(outer) {
315 if (Derived::IsVectorAtCompileTime && mat.outerIndexPtr() == 0) {
316 m_start = 0;
317 m_id = mat.nonZeros();
318 } else {
319 m_start = mat.outerIndexPtr()[outer];
320 if (mat.isCompressed())
321 m_id = mat.outerIndexPtr()[outer + 1];
322 else
323 m_id = m_start + mat.innerNonZeroPtr()[outer];
324 }
325 }
326
327 explicit ReverseInnerIterator(const SparseCompressedBase& mat) : ReverseInnerIterator(mat, Index(0)) {
328 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
329 }
330
331 explicit ReverseInnerIterator(const internal::CompressedStorage<Scalar, StorageIndex>& data)
332 : m_values(data.valuePtr()), m_indices(data.indexPtr()), m_outer(0), m_start(0), m_id(data.size()) {
333 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
334 }
335
336 inline ReverseInnerIterator& operator--() {
337 --m_id;
338 return *this;
339 }
340 inline ReverseInnerIterator& operator-=(Index i) {
341 m_id -= i;
342 return *this;
343 }
344
345 inline ReverseInnerIterator operator-(Index i) {
346 ReverseInnerIterator result = *this;
347 result -= i;
348 return result;
349 }
350
351 inline const Scalar& value() const { return m_values[m_id - 1]; }
352 inline Scalar& valueRef() { return const_cast<Scalar&>(m_values[m_id - 1]); }
353
354 inline StorageIndex index() const { return m_indices[m_id - 1]; }
355 inline Index outer() const { return m_outer.value(); }
356 inline Index row() const { return IsRowMajor ? m_outer.value() : index(); }
357 inline Index col() const { return IsRowMajor ? index() : m_outer.value(); }
358
359 inline operator bool() const { return m_id > m_start; }
360
361 inline bool operator==(const ReverseInnerIterator& other) const {
362 eigen_assert(m_values == other.m_values && "comparing iterators from different sources");
363 return m_outer.value() == other.m_outer.value() && m_id == other.m_id;
364 }
365 inline bool operator!=(const ReverseInnerIterator& other) const { return !(*this == other); }
366
367 protected:
368 const Scalar* m_values;
369 const StorageIndex* m_indices;
370 using OuterType = internal::variable_if_dynamic<Index, Derived::IsVectorAtCompileTime ? 0 : Dynamic>;
371 const OuterType m_outer;
372 Index m_start;
373 Index m_id;
374};
375
376namespace internal {
377
378// modified from https://artificial-mind.net/blog/2020/11/28/std-sort-multiple-ranges
379
380template <typename Scalar, typename StorageIndex>
381class StorageVal;
382template <typename Scalar, typename StorageIndex>
383class StorageRef;
384template <typename Scalar, typename StorageIndex>
385class CompressedStorageIterator;
386
387// class to hold an index/value pair
388template <typename Scalar, typename StorageIndex>
389class StorageVal {
390 public:
391 StorageVal(const StorageIndex& innerIndex, const Scalar& value) : m_innerIndex(innerIndex), m_value(value) {}
392 StorageVal(const StorageVal& other) = default;
393 StorageVal(StorageVal&& other) = default;
394
395 inline const StorageIndex& key() const { return m_innerIndex; }
396 inline StorageIndex& key() { return m_innerIndex; }
397 inline const Scalar& value() const { return m_value; }
398 inline Scalar& value() { return m_value; }
399
400 // enables StorageVal to be compared with respect to any type that is convertible to StorageIndex
401 inline operator StorageIndex() const { return m_innerIndex; }
402
403 protected:
404 StorageIndex m_innerIndex;
405 Scalar m_value;
406
407 private:
408 StorageVal() = delete;
409};
410// class to hold an index/value iterator pair
411// used to define assignment, swap, and comparison operators for CompressedStorageIterator
412template <typename Scalar, typename StorageIndex>
413class StorageRef {
414 public:
415 using value_type = StorageVal<Scalar, StorageIndex>;
416
417 // StorageRef needs to be move-able for sort on macOS.
418 StorageRef(StorageRef&& other) = default;
419
420 inline StorageRef& operator=(const StorageRef& other) {
421 key() = other.key();
422 value() = other.value();
423 return *this;
424 }
425 inline StorageRef& operator=(const value_type& other) {
426 key() = other.key();
427 value() = other.value();
428 return *this;
429 }
430 inline operator value_type() const { return value_type(key(), value()); }
431 inline friend void swap(const StorageRef& a, const StorageRef& b) {
432 std::iter_swap(a.keyPtr(), b.keyPtr());
433 std::iter_swap(a.valuePtr(), b.valuePtr());
434 }
435
436 inline const StorageIndex& key() const { return *m_innerIndexIterator; }
437 inline StorageIndex& key() { return *m_innerIndexIterator; }
438 inline const Scalar& value() const { return *m_valueIterator; }
439 inline Scalar& value() { return *m_valueIterator; }
440 inline StorageIndex* keyPtr() const { return m_innerIndexIterator; }
441 inline Scalar* valuePtr() const { return m_valueIterator; }
442
443 // enables StorageRef to be compared with respect to any type that is convertible to StorageIndex
444 inline operator StorageIndex() const { return *m_innerIndexIterator; }
445
446 protected:
447 StorageIndex* m_innerIndexIterator;
448 Scalar* m_valueIterator;
449
450 private:
451 StorageRef() = delete;
452 // these constructors are called by the CompressedStorageIterator constructors for convenience only
453 StorageRef(StorageIndex* innerIndexIterator, Scalar* valueIterator)
454 : m_innerIndexIterator(innerIndexIterator), m_valueIterator(valueIterator) {}
455 StorageRef(const StorageRef& other) = default;
456
457 friend class CompressedStorageIterator<Scalar, StorageIndex>;
458};
459
460// STL-compatible iterator class that operates on inner indices and values
461template <typename Scalar, typename StorageIndex>
462class CompressedStorageIterator {
463 public:
464 using iterator_category = std::random_access_iterator_tag;
465 using reference = StorageRef<Scalar, StorageIndex>;
466 using difference_type = Index;
467 using value_type = typename reference::value_type;
468 using pointer = value_type*;
469
470 CompressedStorageIterator() = delete;
471 CompressedStorageIterator(difference_type index, StorageIndex* innerIndexPtr, Scalar* valuePtr)
472 : m_index(index), m_data(innerIndexPtr, valuePtr) {}
473 CompressedStorageIterator(difference_type index, reference data) : m_index(index), m_data(data) {}
474 CompressedStorageIterator(const CompressedStorageIterator& other) = default;
475 CompressedStorageIterator(CompressedStorageIterator&& other) = default;
476 inline CompressedStorageIterator& operator=(const CompressedStorageIterator& other) {
477 m_index = other.m_index;
478 m_data = other.m_data;
479 return *this;
480 }
481
482 inline CompressedStorageIterator operator+(difference_type offset) const {
483 return CompressedStorageIterator(m_index + offset, m_data);
484 }
485 inline CompressedStorageIterator operator-(difference_type offset) const {
486 return CompressedStorageIterator(m_index - offset, m_data);
487 }
488 inline difference_type operator-(const CompressedStorageIterator& other) const { return m_index - other.m_index; }
489 inline CompressedStorageIterator& operator++() {
490 ++m_index;
491 return *this;
492 }
493 inline CompressedStorageIterator& operator--() {
494 --m_index;
495 return *this;
496 }
497 inline CompressedStorageIterator& operator+=(difference_type offset) {
498 m_index += offset;
499 return *this;
500 }
501 inline CompressedStorageIterator& operator-=(difference_type offset) {
502 m_index -= offset;
503 return *this;
504 }
505 inline reference operator*() const { return reference(m_data.keyPtr() + m_index, m_data.valuePtr() + m_index); }
506 inline reference operator[](int index) { return *(*this + index); }
507
508#define MAKE_COMP(OP) \
509 inline bool operator OP(const CompressedStorageIterator& other) const { return m_index OP other.m_index; }
510 MAKE_COMP(<)
511 MAKE_COMP(>)
512 MAKE_COMP(>=)
513 MAKE_COMP(<=)
514 MAKE_COMP(!=)
515 MAKE_COMP(==)
516#undef MAKE_COMP
517
518 protected:
519 difference_type m_index;
520 reference m_data;
521};
522
523template <typename Derived, class Comp, bool IsVector>
524struct inner_sort_impl {
525 using Scalar = typename Derived::Scalar;
526 using StorageIndex = typename Derived::StorageIndex;
527 static inline void run(SparseCompressedBase<Derived>& obj, Index begin, Index end) {
528 const bool is_compressed = obj.isCompressed();
529 for (Index outer = begin; outer < end; outer++) {
530 Index begin_offset = obj.outerIndexPtr()[outer];
531 Index end_offset = is_compressed ? obj.outerIndexPtr()[outer + 1] : (begin_offset + obj.innerNonZeroPtr()[outer]);
532 CompressedStorageIterator<Scalar, StorageIndex> begin_it(begin_offset, obj.innerIndexPtr(), obj.valuePtr());
533 CompressedStorageIterator<Scalar, StorageIndex> end_it(end_offset, obj.innerIndexPtr(), obj.valuePtr());
534 std::sort(begin_it, end_it, Comp());
535 }
536 }
537 static inline Index check(const SparseCompressedBase<Derived>& obj, Index begin, Index end) {
538 const bool is_compressed = obj.isCompressed();
539 for (Index outer = begin; outer < end; outer++) {
540 Index begin_offset = obj.outerIndexPtr()[outer];
541 Index end_offset = is_compressed ? obj.outerIndexPtr()[outer + 1] : (begin_offset + obj.innerNonZeroPtr()[outer]);
542 const StorageIndex* begin_it = obj.innerIndexPtr() + begin_offset;
543 const StorageIndex* end_it = obj.innerIndexPtr() + end_offset;
544 bool is_sorted = std::is_sorted(begin_it, end_it, Comp());
545 if (!is_sorted) return outer;
546 }
547 return end;
548 }
549};
550template <typename Derived, class Comp>
551struct inner_sort_impl<Derived, Comp, true> {
552 using Scalar = typename Derived::Scalar;
553 using StorageIndex = typename Derived::StorageIndex;
554 static inline void run(SparseCompressedBase<Derived>& obj, Index, Index) {
555 const StorageIndex* outer = obj.outerIndexPtr();
556 Index begin_offset = (outer && obj.outerSize() > 0) ? internal::convert_index<Index>(outer[0]) : 0;
557 Index end_offset = begin_offset + obj.nonZeros();
558 CompressedStorageIterator<Scalar, StorageIndex> begin_it(begin_offset, obj.innerIndexPtr(), obj.valuePtr());
559 CompressedStorageIterator<Scalar, StorageIndex> end_it(end_offset, obj.innerIndexPtr(), obj.valuePtr());
560 std::sort(begin_it, end_it, Comp());
561 }
562 static inline Index check(const SparseCompressedBase<Derived>& obj, Index, Index) {
563 const StorageIndex* outer = obj.outerIndexPtr();
564 Index begin_offset = (outer && obj.outerSize() > 0) ? internal::convert_index<Index>(outer[0]) : 0;
565 Index end_offset = begin_offset + obj.nonZeros();
566 const StorageIndex* begin_it = obj.innerIndexPtr() + begin_offset;
567 const StorageIndex* end_it = obj.innerIndexPtr() + end_offset;
568 return std::is_sorted(begin_it, end_it, Comp()) ? 1 : 0;
569 }
570};
571
572template <typename Derived>
573struct evaluator<SparseCompressedBase<Derived>> : evaluator_base<Derived> {
574 using Scalar = typename Derived::Scalar;
575 using InnerIterator = typename Derived::InnerIterator;
576
577 enum { CoeffReadCost = NumTraits<Scalar>::ReadCost, Flags = Derived::Flags };
578
579 evaluator() : m_matrix(0) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); }
580 explicit evaluator(const Derived& mat) : m_matrix(&mat) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); }
581
582 inline Index nonZerosEstimate() const { return m_matrix->nonZeros(); }
583
584 operator Derived&() { return m_matrix->const_cast_derived(); }
585 operator const Derived&() const { return *m_matrix; }
586
587 using CoeffReturnType = typename DenseCoeffsBase<Derived, ReadOnlyAccessors>::CoeffReturnType;
588 const Scalar& coeff(Index row, Index col) const {
589 Index p = find(row, col);
590
591 if (p == Dynamic)
592 return zero();
593 else
594 return m_matrix->const_cast_derived().valuePtr()[p];
595 }
596
597 Scalar& coeffRef(Index row, Index col) {
598 Index p = find(row, col);
599 eigen_assert(p != Dynamic && "written coefficient does not exist");
600 return m_matrix->const_cast_derived().valuePtr()[p];
601 }
602
603 protected:
604 Index find(Index row, Index col) const {
605 internal::LowerBoundIndex p = m_matrix->lower_bound(row, col);
606 return p.found ? p.value : Dynamic;
607 }
608
609 // Stable storage for the structural zero coeff() hands out by reference. Kept
610 // out of the evaluator itself: product_evaluator and friends reconstruct their
611 // base evaluator in place with construct_at, which would leak any member that
612 // owns resources when Scalar is not trivially destructible.
613 static const Scalar& zero() {
614 static const Scalar kZero(0);
615 return kZero;
616 }
617
618 const Derived* m_matrix;
619};
620
621} // namespace internal
622
623} // end namespace Eigen
624
625#endif // EIGEN_SPARSE_COMPRESSED_BASE_H
A matrix or vector expression mapping an existing array of data.
Definition Map.h:97
Common base class for sparse [compressed]-{row|column}-storage format.
Definition SparseCompressedBase.h:44
StorageIndex * innerNonZeroPtr()
Definition SparseCompressedBase.h:112
Index nonZeros() const
Definition SparseCompressedBase.h:65
Index innerIndicesAreSorted() const
Definition SparseCompressedBase.h:181
const StorageIndex * innerIndexPtr() const
Definition SparseCompressedBase.h:88
StorageIndex * innerIndexPtr()
Definition SparseCompressedBase.h:92
void sortInnerIndices()
Definition SparseCompressedBase.h:172
const Scalar * valuePtr() const
Definition SparseCompressedBase.h:79
Index innerIndicesAreSorted(Index begin, Index end) const
Definition SparseCompressedBase.h:164
bool isCompressed() const
Definition SparseCompressedBase.h:115
const StorageIndex * outerIndexPtr() const
Definition SparseCompressedBase.h:98
void sortInnerIndices(Index begin, Index end)
Definition SparseCompressedBase.h:156
Scalar * valuePtr()
Definition SparseCompressedBase.h:83
Map< Array< Scalar, Dynamic, 1 > > coeffs()
Definition SparseCompressedBase.h:146
const StorageIndex * innerNonZeroPtr() const
Definition SparseCompressedBase.h:108
StorageIndex * outerIndexPtr()
Definition SparseCompressedBase.h:103
const Map< const Array< Scalar, Dynamic, 1 > > coeffs() const
Definition SparseCompressedBase.h:129
const CwiseBinaryOp< internal::scalar_sum_op< Scalar, typename OtherDerived::Scalar >, const Derived, const OtherDerived > operator+(const Eigen::SparseMatrixBase< OtherDerived > &other) const
Index rows() const
Definition SparseMatrixBase.h:182
constexpr RowXpr row(Index i)
Definition SparseMatrixBase.h:1094
typename internal::traits< BlockType >::StorageIndex StorageIndex
Definition SparseMatrixBase.h:45
Index outerSize() const
Definition SparseMatrixBase.h:195
Index cols() const
Definition SparseMatrixBase.h:184
constexpr const NegativeReturnType operator-() const
Definition SparseMatrixBase.h:48
constexpr ColXpr col(Index i)
Definition SparseMatrixBase.h:1081
bool isCompressed() const
Definition SparseCompressedBase.h:115
constexpr Derived & derived()
Definition EigenBase.h:50
constexpr Index size() const noexcept
Definition EigenBase.h:65
Eigen::Index Index
The interface type of indices.
Definition EigenBase.h:44