Eigen  5.0.1
 
Loading...
Searching...
No Matches
SparseDiagonalProduct.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2009-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_DIAGONAL_PRODUCT_H
12#define EIGEN_SPARSE_DIAGONAL_PRODUCT_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17namespace Eigen {
18
19// The product of a diagonal matrix with a sparse matrix can be easily
20// implemented using expression template.
21// We have to consider two very different cases:
22// 1 - diag * row-major sparse
23// => each inner vector <=> scalar * sparse vector product
24// => so we can reuse CwiseUnaryOp::InnerIterator
25// 2 - diag * col-major sparse
26// => each inner vector <=> densevector * sparse vector cwise product
27// => again, we can reuse specialization of CwiseBinaryOp::InnerIterator
28// for that particular case
29// The two other cases are symmetric.
30
31namespace internal {
32
33enum { SDP_AsScalarProduct, SDP_AsCwiseProduct };
34
35template <typename SparseXprType, typename DiagonalCoeffType, int SDP_Tag>
36struct sparse_diagonal_product_evaluator;
37
38template <typename Lhs, typename Rhs, int ProductTag>
39struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, DiagonalShape, SparseShape>
40 : public sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType,
41 Rhs::Flags & RowMajorBit ? SDP_AsScalarProduct : SDP_AsCwiseProduct> {
42 using XprType = Product<Lhs, Rhs, DefaultProduct>;
43 enum {
44 CoeffReadCost = HugeCost,
45 Flags = Rhs::Flags & RowMajorBit,
46 Alignment = 0
47 }; // FIXME: compute proper CoeffReadCost and propagate Flags.
48
49 using Base = sparse_diagonal_product_evaluator<Rhs, typename Lhs::DiagonalVectorType,
50 Rhs::Flags & RowMajorBit ? SDP_AsScalarProduct : SDP_AsCwiseProduct>;
51 explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) {}
52};
53
54template <typename Lhs, typename Rhs, int ProductTag>
55struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseShape, DiagonalShape>
56 : public sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>,
57 Lhs::Flags & RowMajorBit ? SDP_AsCwiseProduct : SDP_AsScalarProduct> {
58 using XprType = Product<Lhs, Rhs, DefaultProduct>;
59 enum {
60 CoeffReadCost = HugeCost,
61 Flags = Lhs::Flags & RowMajorBit,
62 Alignment = 0
63 }; // FIXME: compute proper CoeffReadCost and propagate Flags.
64
65 using Base = sparse_diagonal_product_evaluator<Lhs, Transpose<const typename Rhs::DiagonalVectorType>,
66 Lhs::Flags & RowMajorBit ? SDP_AsCwiseProduct : SDP_AsScalarProduct>;
67 explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal().transpose()) {}
68};
69
70// SparseSelfAdjointView synthesizes mirrored entries; build the diagonal-scaled
71// full result directly instead of first materializing an unscaled PlainObject.
72template <int Mode, int ProductOrder, typename SelfAdjointViewType, typename DiagonalType, typename Dest>
73struct sparse_selfadjoint_diagonal_product_impl {
74 using MatrixType = typename SelfAdjointViewType::MatrixTypeNested_;
75 using MatrixEvaluator = evaluator<MatrixType>;
76 using MatrixIterator = typename MatrixEvaluator::InnerIterator;
77 using StorageIndex = typename Dest::StorageIndex;
78 using VectorI = Matrix<StorageIndex, Dynamic, 1>;
79 enum { IsFullMode = Mode == int(Upper | Lower), IsLowerMode = (Mode & int(Lower)) == int(Lower) };
80
81 static void run(Dest& dest, const SelfAdjointViewType& selfadjoint, const DiagonalType& diagonal) {
82 MatrixEvaluator matrixEval(selfadjoint.matrix());
83 const Index size = selfadjoint.rows();
84 VectorI count(size);
85 count.setZero();
86 dest.resize(size, size);
87
88 for (Index outer = 0; outer < selfadjoint.matrix().outerSize(); ++outer) {
89 for (MatrixIterator it(matrixEval, outer); it; ++it) countEntry(count, it.row(), it.col());
90 }
91
92 Index nnz = count.sum();
93 dest.resizeNonZeros(nnz);
94 dest.outerIndexPtr()[0] = 0;
95 for (Index outer = 0; outer < size; ++outer)
96 dest.outerIndexPtr()[outer + 1] = dest.outerIndexPtr()[outer] + count[outer];
97 for (Index outer = 0; outer < size; ++outer) count[outer] = dest.outerIndexPtr()[outer];
98
99 for (Index outer = 0; outer < selfadjoint.matrix().outerSize(); ++outer) {
100 for (MatrixIterator it(matrixEval, outer); it; ++it) {
101 const Index row = it.row();
102 const Index col = it.col();
103 if (isStored(row, col)) {
104 insertEntry(dest, count, diagonal, row, col, it.value());
105 }
106 if (mirrorsStoredEntry(row, col)) {
107 insertEntry(dest, count, diagonal, col, row, numext::conj(it.value()));
108 }
109 }
110 }
111 }
112
113 private:
114 static EIGEN_STRONG_INLINE bool isStored(Index row, Index col) {
115 return IsFullMode || row == col || (IsLowerMode ? row > col : row < col);
116 }
117
118 static EIGEN_STRONG_INLINE bool mirrorsStoredEntry(Index row, Index col) {
119 return !IsFullMode && row != col && (IsLowerMode ? row > col : row < col);
120 }
121
122 static void countEntry(VectorI& count, Index row, Index col) {
123 if (isStored(row, col)) {
124 ++count[outerIndex(row, col)];
125 }
126 if (mirrorsStoredEntry(row, col)) {
127 ++count[outerIndex(col, row)];
128 }
129 }
130
131 static EIGEN_STRONG_INLINE StorageIndex outerIndex(Index row, Index col) {
132 return internal::convert_index<StorageIndex>(Dest::IsRowMajor ? row : col);
133 }
134
135 static EIGEN_STRONG_INLINE StorageIndex innerIndex(Index row, Index col) {
136 return internal::convert_index<StorageIndex>(Dest::IsRowMajor ? col : row);
137 }
138
139 template <typename Coeff>
140 static void insertEntry(Dest& dest, VectorI& count, const DiagonalType& diagonal, Index row, Index col,
141 const Coeff& coeff) {
142 const StorageIndex outer = outerIndex(row, col);
143 const Index k = count[outer]++;
144 dest.innerIndexPtr()[k] = innerIndex(row, col);
145 EIGEN_IF_CONSTEXPR (ProductOrder == OnTheLeft) {
146 dest.valuePtr()[k] = diagonal.coeff(row) * coeff;
147 } else {
148 dest.valuePtr()[k] = coeff * diagonal.coeff(col);
149 }
150 }
151};
152
153template <typename Lhs, typename Rhs>
154struct materialized_left_sparse_product_evaluator_base
155 : public evaluator<typename Product<Lhs, typename Rhs::PlainObject, DefaultProduct>::PlainObject> {
156 using XprType = Product<Lhs, Rhs, DefaultProduct>;
157 using PlainObject = typename XprType::PlainObject;
158 using Base = evaluator<PlainObject>;
159
160 explicit materialized_left_sparse_product_evaluator_base(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) {
161 internal::construct_at<Base>(this, m_result);
162 sparse_selfadjoint_diagonal_product_impl<Rhs::Mode, OnTheLeft, Rhs, typename Lhs::DiagonalVectorType,
163 PlainObject>::run(m_result, xpr.rhs(), xpr.lhs().diagonal());
164 }
165
166 protected:
167 PlainObject m_result;
168};
169
170template <typename Lhs, typename Rhs>
171struct materialized_right_sparse_product_evaluator_base
172 : public evaluator<typename Product<typename Lhs::PlainObject, Rhs, DefaultProduct>::PlainObject> {
173 using XprType = Product<Lhs, Rhs, DefaultProduct>;
174 using PlainObject = typename XprType::PlainObject;
175 using Base = evaluator<PlainObject>;
176
177 explicit materialized_right_sparse_product_evaluator_base(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) {
178 internal::construct_at<Base>(this, m_result);
179 sparse_selfadjoint_diagonal_product_impl<Lhs::Mode, OnTheRight, Lhs, typename Rhs::DiagonalVectorType,
180 PlainObject>::run(m_result, xpr.lhs(), xpr.rhs().diagonal());
181 }
182
183 protected:
184 PlainObject m_result;
185};
186
187template <typename Lhs, typename Rhs, int ProductTag>
188struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, DiagonalShape, SparseTriangularShape>
189 : product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, DiagonalShape, SparseShape> {
190 using Base = product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, DiagonalShape, SparseShape>;
191 using Base::Base;
192};
193
194template <typename Lhs, typename Rhs, int ProductTag>
195struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, DiagonalShape, SparseSelfAdjointShape>
196 : materialized_left_sparse_product_evaluator_base<Lhs, Rhs> {
197 using materialized_left_sparse_product_evaluator_base<Lhs, Rhs>::materialized_left_sparse_product_evaluator_base;
198};
199
200template <typename Lhs, typename Rhs, int ProductTag>
201struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseTriangularShape, DiagonalShape>
202 : product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseShape, DiagonalShape> {
203 using Base = product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseShape, DiagonalShape>;
204 using Base::Base;
205};
206
207template <typename Lhs, typename Rhs, int ProductTag>
208struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, ProductTag, SparseSelfAdjointShape, DiagonalShape>
209 : materialized_right_sparse_product_evaluator_base<Lhs, Rhs> {
210 using materialized_right_sparse_product_evaluator_base<Lhs, Rhs>::materialized_right_sparse_product_evaluator_base;
211};
212
213template <typename SparseXprType, typename DiagonalCoeffType>
214struct sparse_diagonal_product_evaluator<SparseXprType, DiagonalCoeffType, SDP_AsScalarProduct> {
215 protected:
216 using SparseXprInnerIterator = typename evaluator<SparseXprType>::InnerIterator;
217 using Scalar = typename SparseXprType::Scalar;
218
219 public:
220 class InnerIterator : public SparseXprInnerIterator {
221 public:
222 InnerIterator(const sparse_diagonal_product_evaluator& xprEval, Index outer)
223 : SparseXprInnerIterator(xprEval.m_sparseXprImpl, outer), m_coeff(xprEval.m_diagCoeffImpl.coeff(outer)) {}
224
225 EIGEN_STRONG_INLINE Scalar value() const { return m_coeff * SparseXprInnerIterator::value(); }
226
227 protected:
228 typename DiagonalCoeffType::Scalar m_coeff;
229 };
230
231 sparse_diagonal_product_evaluator(const SparseXprType& sparseXpr, const DiagonalCoeffType& diagCoeff)
232 : m_sparseXprImpl(sparseXpr), m_diagCoeffImpl(diagCoeff) {}
233
234 Index nonZerosEstimate() const { return m_sparseXprImpl.nonZerosEstimate(); }
235
236 protected:
237 evaluator<SparseXprType> m_sparseXprImpl;
238 evaluator<DiagonalCoeffType> m_diagCoeffImpl;
239};
240
241template <typename SparseXprType, typename DiagCoeffType>
242struct sparse_diagonal_product_evaluator<SparseXprType, DiagCoeffType, SDP_AsCwiseProduct> {
243 using Scalar = typename SparseXprType::Scalar;
244 using StorageIndex = typename SparseXprType::StorageIndex;
245
246 using DiagCoeffNested =
247 typename nested_eval<DiagCoeffType, SparseXprType::IsRowMajor ? SparseXprType::RowsAtCompileTime
248 : SparseXprType::ColsAtCompileTime>::type;
249
250 class InnerIterator {
251 using SparseXprIter = typename evaluator<SparseXprType>::InnerIterator;
252
253 public:
254 InnerIterator(const sparse_diagonal_product_evaluator& xprEval, Index outer)
255 : m_sparseIter(xprEval.m_sparseXprEval, outer), m_diagCoeffNested(xprEval.m_diagCoeffNested) {}
256
257 inline Scalar value() const { return m_sparseIter.value() * m_diagCoeffNested.coeff(index()); }
258 inline StorageIndex index() const { return m_sparseIter.index(); }
259 inline Index outer() const { return m_sparseIter.outer(); }
260 inline Index col() const { return SparseXprType::IsRowMajor ? m_sparseIter.index() : m_sparseIter.outer(); }
261 inline Index row() const { return SparseXprType::IsRowMajor ? m_sparseIter.outer() : m_sparseIter.index(); }
262
263 EIGEN_STRONG_INLINE InnerIterator& operator++() {
264 ++m_sparseIter;
265 return *this;
266 }
267 inline operator bool() const { return m_sparseIter; }
268
269 protected:
270 SparseXprIter m_sparseIter;
271 DiagCoeffNested m_diagCoeffNested;
272 };
273
274 sparse_diagonal_product_evaluator(const SparseXprType& sparseXpr, const DiagCoeffType& diagCoeff)
275 : m_sparseXprEval(sparseXpr), m_diagCoeffNested(diagCoeff) {}
276
277 Index nonZerosEstimate() const { return m_sparseXprEval.nonZerosEstimate(); }
278
279 protected:
280 evaluator<SparseXprType> m_sparseXprEval;
281 DiagCoeffNested m_diagCoeffNested;
282};
283
284} // end namespace internal
285
286} // end namespace Eigen
287
288#endif // EIGEN_SPARSE_DIAGONAL_PRODUCT_H
@ Lower
Definition Constants.h:212
@ Upper
Definition Constants.h:214
@ OnTheLeft
Definition Constants.h:332
@ OnTheRight
Definition Constants.h:334
constexpr unsigned int RowMajorBit
Definition Constants.h:71