Eigen  5.0.1
 
Loading...
Searching...
No Matches
SparseCwiseBinaryOp.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008-2014 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_CWISE_BINARY_OP_H
12#define EIGEN_SPARSE_CWISE_BINARY_OP_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17namespace Eigen {
18
19// Here we have to handle 3 cases:
20// 1 - sparse op dense
21// 2 - dense op sparse
22// 3 - sparse op sparse
23// We also need to implement a 4th iterator for:
24// 4 - dense op dense
25// Finally, we also need to distinguish between the product and other operations :
26// configuration returned mode
27// 1 - sparse op dense product sparse
28// generic dense
29// 2 - dense op sparse product sparse
30// generic dense
31// 3 - sparse op sparse product sparse
32// generic sparse
33// 4 - dense op dense product dense
34// generic dense
35//
36// TODO: to ease compiler job, we could specialize product/quotient with a scalar
37// and fallback to cwise-unary evaluator using bind1st_op and bind2nd_op.
38
39template <typename BinaryOp, typename Lhs, typename Rhs>
40class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Sparse> : public SparseMatrixBase<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > {
41 public:
42 using Derived = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
43 using Base = SparseMatrixBase<Derived>;
44 EIGEN_SPARSE_PUBLIC_INTERFACE(Derived)
45 EIGEN_STATIC_ASSERT(((!std::is_same<typename internal::traits<Lhs>::StorageKind,
46 typename internal::traits<Rhs>::StorageKind>::value) ||
47 ((internal::evaluator<Lhs>::Flags & RowMajorBit) ==
48 (internal::evaluator<Rhs>::Flags & RowMajorBit))),
49 THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH)
50};
51
52namespace internal {
53
54// The default evaluator performs an "arithmetic" operation on two input arrays.
55// Given input arrays 'lhs' and 'rhs' and binary functor 'func',
56// the sparse destination array 'dst' is evaluated as follows:
57// if lhs(i,j) and rhs(i,j) are present, dst(i,j) = func(lhs(i,j), rhs(i,j))
58// if lhs(i,j) is present and rhs(i,j) is null, dst(i,j) = func(lhs(i,j), 0)
59// if lhs(i,j) is null and rhs(i,j) is present, dst(i,j) = func(0, rhs(i,j))
60
61// Generic "sparse OP sparse"
62template <typename BinaryOp, typename Lhs, typename Rhs>
63struct binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IteratorBased, IteratorBased>
64 : evaluator_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > {
65 protected:
66 using LhsIterator = typename evaluator<Lhs>::InnerIterator;
67 using RhsIterator = typename evaluator<Rhs>::InnerIterator;
68 using XprType = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
69 using Scalar = typename traits<XprType>::Scalar;
70 using StorageIndex = typename XprType::StorageIndex;
71
72 public:
73 class InnerIterator {
74 public:
75 EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer)
76 : m_lhsIter(aEval.m_lhsImpl, outer),
77 m_rhsIter(aEval.m_rhsImpl, outer),
78 m_functor(aEval.m_functor),
79 m_value(Scalar(0)) {
80 this->operator++();
81 }
82
83 EIGEN_STRONG_INLINE InnerIterator& operator++() {
84 if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) {
85 m_id = m_lhsIter.index();
86 m_value = m_functor(m_lhsIter.value(), m_rhsIter.value());
87 ++m_lhsIter;
88 ++m_rhsIter;
89 } else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) {
90 m_id = m_lhsIter.index();
91 m_value = m_functor(m_lhsIter.value(), Scalar(0));
92 ++m_lhsIter;
93 } else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) {
94 m_id = m_rhsIter.index();
95 m_value = m_functor(Scalar(0), m_rhsIter.value());
96 ++m_rhsIter;
97 } else {
98 m_id = -1;
99 }
100 return *this;
101 }
102
103 EIGEN_STRONG_INLINE Scalar value() const { return m_value; }
104
105 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
106 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
107 EIGEN_STRONG_INLINE Index row() const { return Lhs::IsRowMajor ? m_lhsIter.row() : index(); }
108 EIGEN_STRONG_INLINE Index col() const { return Lhs::IsRowMajor ? index() : m_lhsIter.col(); }
109
110 EIGEN_STRONG_INLINE operator bool() const { return m_id >= 0; }
111
112 protected:
113 LhsIterator m_lhsIter;
114 RhsIterator m_rhsIter;
115 const BinaryOp& m_functor;
116 Scalar m_value;
117 StorageIndex m_id;
118 };
119
120 enum {
121 CoeffReadCost =
122 int(evaluator<Lhs>::CoeffReadCost) + int(evaluator<Rhs>::CoeffReadCost) + int(functor_traits<BinaryOp>::Cost),
123 Flags = XprType::Flags
124 };
125
126 explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) {
127 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
128 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
129 }
130
131 inline Index nonZerosEstimate() const { return m_lhsImpl.nonZerosEstimate() + m_rhsImpl.nonZerosEstimate(); }
132
133 protected:
134 const BinaryOp m_functor;
135 evaluator<Lhs> m_lhsImpl;
136 evaluator<Rhs> m_rhsImpl;
137};
138
139// dense op sparse
140template <typename BinaryOp, typename Lhs, typename Rhs>
141struct binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IndexBased, IteratorBased>
142 : evaluator_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > {
143 protected:
144 using RhsIterator = typename evaluator<Rhs>::InnerIterator;
145 using XprType = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
146 using Scalar = typename traits<XprType>::Scalar;
147 using StorageIndex = typename XprType::StorageIndex;
148
149 public:
150 class InnerIterator {
151 enum { IsRowMajor = (int(Rhs::Flags) & RowMajorBit) == RowMajorBit };
152
153 public:
154 EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer)
155 : m_lhsEval(aEval.m_lhsImpl),
156 m_rhsIter(aEval.m_rhsImpl, outer),
157 m_functor(aEval.m_functor),
158 m_value(0),
159 m_id(-1),
160 m_innerSize(aEval.m_expr.rhs().innerSize()) {
161 this->operator++();
162 }
163
164 EIGEN_STRONG_INLINE InnerIterator& operator++() {
165 ++m_id;
166 if (m_id < m_innerSize) {
167 Scalar lhsVal = m_lhsEval.coeff(IsRowMajor ? m_rhsIter.outer() : m_id, IsRowMajor ? m_id : m_rhsIter.outer());
168 if (m_rhsIter && m_rhsIter.index() == m_id) {
169 m_value = m_functor(lhsVal, m_rhsIter.value());
170 ++m_rhsIter;
171 } else
172 m_value = m_functor(lhsVal, Scalar(0));
173 }
174
175 return *this;
176 }
177
178 EIGEN_STRONG_INLINE Scalar value() const {
179 eigen_internal_assert(m_id < m_innerSize);
180 return m_value;
181 }
182
183 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
184 EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); }
185 EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_rhsIter.outer() : m_id; }
186 EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_rhsIter.outer(); }
187
188 EIGEN_STRONG_INLINE operator bool() const { return m_id < m_innerSize; }
189
190 protected:
191 const evaluator<Lhs>& m_lhsEval;
192 RhsIterator m_rhsIter;
193 const BinaryOp& m_functor;
194 Scalar m_value;
195 StorageIndex m_id;
196 StorageIndex m_innerSize;
197 };
198
199 enum {
200 CoeffReadCost =
201 int(evaluator<Lhs>::CoeffReadCost) + int(evaluator<Rhs>::CoeffReadCost) + int(functor_traits<BinaryOp>::Cost),
202 Flags = XprType::Flags
203 };
204
205 explicit binary_evaluator(const XprType& xpr)
206 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_expr(xpr) {
207 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
208 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
209 }
210
211 inline Index nonZerosEstimate() const { return m_expr.size(); }
212
213 protected:
214 const BinaryOp m_functor;
215 evaluator<Lhs> m_lhsImpl;
216 evaluator<Rhs> m_rhsImpl;
217 const XprType& m_expr;
218};
219
220// sparse op dense
221template <typename BinaryOp, typename Lhs, typename Rhs>
222struct binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IteratorBased, IndexBased>
223 : evaluator_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > {
224 protected:
225 using LhsIterator = typename evaluator<Lhs>::InnerIterator;
226 using XprType = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
227 using Scalar = typename traits<XprType>::Scalar;
228 using StorageIndex = typename XprType::StorageIndex;
229
230 public:
231 class InnerIterator {
232 enum { IsRowMajor = (int(Lhs::Flags) & RowMajorBit) == RowMajorBit };
233
234 public:
235 EIGEN_STRONG_INLINE InnerIterator(const binary_evaluator& aEval, Index outer)
236 : m_lhsIter(aEval.m_lhsImpl, outer),
237 m_rhsEval(aEval.m_rhsImpl),
238 m_functor(aEval.m_functor),
239 m_value(0),
240 m_id(-1),
241 m_innerSize(aEval.m_expr.lhs().innerSize()) {
242 this->operator++();
243 }
244
245 EIGEN_STRONG_INLINE InnerIterator& operator++() {
246 ++m_id;
247 if (m_id < m_innerSize) {
248 Scalar rhsVal = m_rhsEval.coeff(IsRowMajor ? m_lhsIter.outer() : m_id, IsRowMajor ? m_id : m_lhsIter.outer());
249 if (m_lhsIter && m_lhsIter.index() == m_id) {
250 m_value = m_functor(m_lhsIter.value(), rhsVal);
251 ++m_lhsIter;
252 } else
253 m_value = m_functor(Scalar(0), rhsVal);
254 }
255
256 return *this;
257 }
258
259 EIGEN_STRONG_INLINE Scalar value() const {
260 eigen_internal_assert(m_id < m_innerSize);
261 return m_value;
262 }
263
264 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
265 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
266 EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_lhsIter.outer() : m_id; }
267 EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_lhsIter.outer(); }
268
269 EIGEN_STRONG_INLINE operator bool() const { return m_id < m_innerSize; }
270
271 protected:
272 LhsIterator m_lhsIter;
273 const evaluator<Rhs>& m_rhsEval;
274 const BinaryOp& m_functor;
275 Scalar m_value;
276 StorageIndex m_id;
277 StorageIndex m_innerSize;
278 };
279
280 enum {
281 CoeffReadCost =
282 int(evaluator<Lhs>::CoeffReadCost) + int(evaluator<Rhs>::CoeffReadCost) + int(functor_traits<BinaryOp>::Cost),
283 Flags = XprType::Flags
284 };
285
286 explicit binary_evaluator(const XprType& xpr)
287 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_expr(xpr) {
288 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
289 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
290 }
291
292 inline Index nonZerosEstimate() const { return m_expr.size(); }
293
294 protected:
295 const BinaryOp m_functor;
296 evaluator<Lhs> m_lhsImpl;
297 evaluator<Rhs> m_rhsImpl;
298 const XprType& m_expr;
299};
300
301template <typename T, typename LhsKind = typename evaluator_traits<typename T::Lhs>::Kind,
302 typename RhsKind = typename evaluator_traits<typename T::Rhs>::Kind,
303 typename LhsScalar = typename traits<typename T::Lhs>::Scalar,
304 typename RhsScalar = typename traits<typename T::Rhs>::Scalar>
305struct sparse_conjunction_evaluator;
306
307// "sparse .* sparse"
308template <typename T1, typename T2, typename Lhs, typename Rhs>
309struct binary_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>, IteratorBased, IteratorBased>
310 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs> > {
311 using XprType = CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>;
312 using Base = sparse_conjunction_evaluator<XprType>;
313 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
314};
315// "dense .* sparse"
316template <typename T1, typename T2, typename Lhs, typename Rhs>
317struct binary_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>, IndexBased, IteratorBased>
318 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs> > {
319 using XprType = CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>;
320 using Base = sparse_conjunction_evaluator<XprType>;
321 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
322};
323// "sparse .* dense"
324template <typename T1, typename T2, typename Lhs, typename Rhs>
325struct binary_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>, IteratorBased, IndexBased>
326 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs> > {
327 using XprType = CwiseBinaryOp<scalar_product_op<T1, T2>, Lhs, Rhs>;
328 using Base = sparse_conjunction_evaluator<XprType>;
329 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
330};
331
332// "sparse ./ dense"
333template <typename T1, typename T2, typename Lhs, typename Rhs>
334struct binary_evaluator<CwiseBinaryOp<scalar_quotient_op<T1, T2>, Lhs, Rhs>, IteratorBased, IndexBased>
335 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_quotient_op<T1, T2>, Lhs, Rhs> > {
336 using XprType = CwiseBinaryOp<scalar_quotient_op<T1, T2>, Lhs, Rhs>;
337 using Base = sparse_conjunction_evaluator<XprType>;
338 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
339};
340
341// "sparse && sparse"
342template <typename Lhs, typename Rhs>
343struct binary_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>, IteratorBased, IteratorBased>
344 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs> > {
345 using XprType = CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>;
346 using Base = sparse_conjunction_evaluator<XprType>;
347 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
348};
349// "dense && sparse"
350template <typename Lhs, typename Rhs>
351struct binary_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>, IndexBased, IteratorBased>
352 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs> > {
353 using XprType = CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>;
354 using Base = sparse_conjunction_evaluator<XprType>;
355 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
356};
357// "sparse && dense"
358template <typename Lhs, typename Rhs>
359struct binary_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>, IteratorBased, IndexBased>
360 : sparse_conjunction_evaluator<CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs> > {
361 using XprType = CwiseBinaryOp<scalar_boolean_and_op<bool>, Lhs, Rhs>;
362 using Base = sparse_conjunction_evaluator<XprType>;
363 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
364};
365
366// The conjunction "^" evaluator performs a logical "and" or set "intersection" operation on two input arrays.
367// Given input arrays 'lhs' and 'rhs' and binary functor 'func',
368// the sparse destination array 'dst' is evaluated as follows:
369// if lhs(i,j) and rhs(i,j) are present, dst(i,j) = func(lhs(i,j), rhs(i,j))
370// if lhs(i,j) is present and rhs(i,j) is null, dst(i,j) is null
371// if lhs(i,j) is null and rhs(i,j) is present, dst(i,j) is null
372
373// "sparse ^ sparse"
374template <typename XprType>
375struct sparse_conjunction_evaluator<XprType, IteratorBased, IteratorBased> : evaluator_base<XprType> {
376 protected:
377 using BinaryOp = typename XprType::Functor;
378 using LhsArg = typename XprType::Lhs;
379 using RhsArg = typename XprType::Rhs;
380 using LhsIterator = typename evaluator<LhsArg>::InnerIterator;
381 using RhsIterator = typename evaluator<RhsArg>::InnerIterator;
382 using StorageIndex = typename XprType::StorageIndex;
383 using Scalar = typename traits<XprType>::Scalar;
384
385 public:
386 class InnerIterator {
387 public:
388 EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer)
389 : m_lhsIter(aEval.m_lhsImpl, outer), m_rhsIter(aEval.m_rhsImpl, outer), m_functor(aEval.m_functor) {
390 while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) {
391 if (m_lhsIter.index() < m_rhsIter.index())
392 ++m_lhsIter;
393 else
394 ++m_rhsIter;
395 }
396 }
397
398 EIGEN_STRONG_INLINE InnerIterator& operator++() {
399 ++m_lhsIter;
400 ++m_rhsIter;
401 while (m_lhsIter && m_rhsIter && (m_lhsIter.index() != m_rhsIter.index())) {
402 if (m_lhsIter.index() < m_rhsIter.index())
403 ++m_lhsIter;
404 else
405 ++m_rhsIter;
406 }
407 return *this;
408 }
409
410 EIGEN_STRONG_INLINE Scalar value() const { return m_functor(m_lhsIter.value(), m_rhsIter.value()); }
411
412 EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); }
413 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
414 EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); }
415 EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); }
416
417 EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter && m_rhsIter; }
418
419 protected:
420 LhsIterator m_lhsIter;
421 RhsIterator m_rhsIter;
422 const BinaryOp& m_functor;
423 };
424
425 enum {
426 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
427 int(functor_traits<BinaryOp>::Cost),
428 Flags = XprType::Flags
429 };
430
431 explicit sparse_conjunction_evaluator(const XprType& xpr)
432 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) {
433 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
434 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
435 }
436
437 inline Index nonZerosEstimate() const {
438 return (std::min)(m_lhsImpl.nonZerosEstimate(), m_rhsImpl.nonZerosEstimate());
439 }
440
441 protected:
442 const BinaryOp m_functor;
443 evaluator<LhsArg> m_lhsImpl;
444 evaluator<RhsArg> m_rhsImpl;
445};
446
447// "dense ^ sparse"
448template <typename XprType>
449struct sparse_conjunction_evaluator<XprType, IndexBased, IteratorBased> : evaluator_base<XprType> {
450 protected:
451 using BinaryOp = typename XprType::Functor;
452 using LhsArg = typename XprType::Lhs;
453 using RhsArg = typename XprType::Rhs;
454 using LhsEvaluator = evaluator<LhsArg>;
455 using RhsIterator = typename evaluator<RhsArg>::InnerIterator;
456 using StorageIndex = typename XprType::StorageIndex;
457 using Scalar = typename traits<XprType>::Scalar;
458
459 public:
460 class InnerIterator {
461 enum { IsRowMajor = (int(RhsArg::Flags) & RowMajorBit) == RowMajorBit };
462
463 public:
464 EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer)
465 : m_lhsEval(aEval.m_lhsImpl), m_rhsIter(aEval.m_rhsImpl, outer), m_functor(aEval.m_functor), m_outer(outer) {}
466
467 EIGEN_STRONG_INLINE InnerIterator& operator++() {
468 ++m_rhsIter;
469 return *this;
470 }
471
472 EIGEN_STRONG_INLINE Scalar value() const {
473 return m_functor(
474 m_lhsEval.coeff(IsRowMajor ? m_outer : m_rhsIter.index(), IsRowMajor ? m_rhsIter.index() : m_outer),
475 m_rhsIter.value());
476 }
477
478 EIGEN_STRONG_INLINE StorageIndex index() const { return m_rhsIter.index(); }
479 EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); }
480 EIGEN_STRONG_INLINE Index row() const { return m_rhsIter.row(); }
481 EIGEN_STRONG_INLINE Index col() const { return m_rhsIter.col(); }
482
483 EIGEN_STRONG_INLINE operator bool() const { return m_rhsIter; }
484
485 protected:
486 const LhsEvaluator& m_lhsEval;
487 RhsIterator m_rhsIter;
488 const BinaryOp& m_functor;
489 const Index m_outer;
490 };
491
492 enum {
493 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
494 int(functor_traits<BinaryOp>::Cost),
495 Flags = XprType::Flags
496 };
497
498 explicit sparse_conjunction_evaluator(const XprType& xpr)
499 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) {
500 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
501 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
502 }
503
504 inline Index nonZerosEstimate() const { return m_rhsImpl.nonZerosEstimate(); }
505
506 protected:
507 const BinaryOp m_functor;
508 evaluator<LhsArg> m_lhsImpl;
509 evaluator<RhsArg> m_rhsImpl;
510};
511
512// "sparse ^ dense"
513template <typename XprType>
514struct sparse_conjunction_evaluator<XprType, IteratorBased, IndexBased> : evaluator_base<XprType> {
515 protected:
516 using BinaryOp = typename XprType::Functor;
517 using LhsArg = typename XprType::Lhs;
518 using RhsArg = typename XprType::Rhs;
519 using LhsIterator = typename evaluator<LhsArg>::InnerIterator;
520 using StorageIndex = typename XprType::StorageIndex;
521 using Scalar = typename traits<XprType>::Scalar;
522
523 public:
524 class InnerIterator {
525 enum { IsRowMajor = (int(LhsArg::Flags) & RowMajorBit) == RowMajorBit };
526
527 public:
528 EIGEN_STRONG_INLINE InnerIterator(const sparse_conjunction_evaluator& aEval, Index outer)
529 : m_lhsIter(aEval.m_lhsImpl, outer), m_rhsEval(aEval.m_rhsImpl), m_functor(aEval.m_functor), m_outer(outer) {}
530
531 EIGEN_STRONG_INLINE InnerIterator& operator++() {
532 ++m_lhsIter;
533 return *this;
534 }
535
536 EIGEN_STRONG_INLINE Scalar value() const {
537 return m_functor(m_lhsIter.value(), m_rhsEval.coeff(IsRowMajor ? m_outer : m_lhsIter.index(),
538 IsRowMajor ? m_lhsIter.index() : m_outer));
539 }
540
541 EIGEN_STRONG_INLINE StorageIndex index() const { return m_lhsIter.index(); }
542 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
543 EIGEN_STRONG_INLINE Index row() const { return m_lhsIter.row(); }
544 EIGEN_STRONG_INLINE Index col() const { return m_lhsIter.col(); }
545
546 EIGEN_STRONG_INLINE operator bool() const { return m_lhsIter; }
547
548 protected:
549 LhsIterator m_lhsIter;
550 const evaluator<RhsArg>& m_rhsEval;
551 const BinaryOp& m_functor;
552 const Index m_outer;
553 };
554
555 enum {
556 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
557 int(functor_traits<BinaryOp>::Cost),
558 Flags = XprType::Flags
559 };
560
561 explicit sparse_conjunction_evaluator(const XprType& xpr)
562 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) {
563 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
564 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
565 }
566
567 inline Index nonZerosEstimate() const { return m_lhsImpl.nonZerosEstimate(); }
568
569 protected:
570 const BinaryOp m_functor;
571 evaluator<LhsArg> m_lhsImpl;
572 evaluator<RhsArg> m_rhsImpl;
573};
574
575template <typename T, typename LhsKind = typename evaluator_traits<typename T::Lhs>::Kind,
576 typename RhsKind = typename evaluator_traits<typename T::Rhs>::Kind,
577 typename LhsScalar = typename traits<typename T::Lhs>::Scalar,
578 typename RhsScalar = typename traits<typename T::Rhs>::Scalar>
579struct sparse_disjunction_evaluator;
580
581// The disjunction "v" evaluator performs a logical "or" or set "union" operation on two input arrays.
582// Given input arrays 'lhs' and 'rhs' and binary functor 'func',
583// the sparse destination array 'dst' is evaluated as follows:
584// if lhs(i,j) and rhs(i,j) are present, dst(i,j) = func(lhs(i,j), rhs(i,j))
585// if lhs(i,j) is present and rhs(i,j) is null, dst(i,j) = lhs(i,j)
586// if lhs(i,j) is null and rhs(i,j) is present, dst(i,j) = rhs(i,j)
587
588// "sparse v sparse"
589template <typename XprType>
590struct sparse_disjunction_evaluator<XprType, IteratorBased, IteratorBased> : evaluator_base<XprType> {
591 protected:
592 using BinaryOp = typename XprType::Functor;
593 using LhsArg = typename XprType::Lhs;
594 using RhsArg = typename XprType::Rhs;
595 using LhsIterator = typename evaluator<LhsArg>::InnerIterator;
596 using RhsIterator = typename evaluator<RhsArg>::InnerIterator;
597 using StorageIndex = typename XprType::StorageIndex;
598 using Scalar = typename traits<XprType>::Scalar;
599
600 public:
601 class InnerIterator {
602 public:
603 EIGEN_STRONG_INLINE InnerIterator(const sparse_disjunction_evaluator& aEval, Index outer)
604 : m_lhsIter(aEval.m_lhsImpl, outer),
605 m_rhsIter(aEval.m_rhsImpl, outer),
606 m_functor(aEval.m_functor),
607 m_value(Scalar(0)) {
608 this->operator++();
609 }
610
611 EIGEN_STRONG_INLINE InnerIterator& operator++() {
612 if (m_lhsIter && m_rhsIter && (m_lhsIter.index() == m_rhsIter.index())) {
613 m_id = m_lhsIter.index();
614 m_value = m_functor(m_lhsIter.value(), m_rhsIter.value());
615 ++m_lhsIter;
616 ++m_rhsIter;
617 } else if (m_lhsIter && (!m_rhsIter || (m_lhsIter.index() < m_rhsIter.index()))) {
618 m_id = m_lhsIter.index();
619 m_value = m_lhsIter.value();
620 ++m_lhsIter;
621 } else if (m_rhsIter && (!m_lhsIter || (m_lhsIter.index() > m_rhsIter.index()))) {
622 m_id = m_rhsIter.index();
623 m_value = m_rhsIter.value();
624 ++m_rhsIter;
625 } else {
626 m_id = -1;
627 }
628 return *this;
629 }
630
631 EIGEN_STRONG_INLINE Scalar value() const { return m_value; }
632
633 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
634 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
635 EIGEN_STRONG_INLINE Index row() const { return LhsArg::IsRowMajor ? m_lhsIter.row() : index(); }
636 EIGEN_STRONG_INLINE Index col() const { return LhsArg::IsRowMajor ? index() : m_lhsIter.col(); }
637
638 EIGEN_STRONG_INLINE operator bool() const { return m_id >= 0; }
639
640 protected:
641 LhsIterator m_lhsIter;
642 RhsIterator m_rhsIter;
643 const BinaryOp& m_functor;
644 Scalar m_value;
645 StorageIndex m_id;
646 };
647
648 enum {
649 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
650 int(functor_traits<BinaryOp>::Cost),
651 Flags = XprType::Flags
652 };
653
654 explicit sparse_disjunction_evaluator(const XprType& xpr)
655 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) {
656 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
657 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
658 }
659
660 inline Index nonZerosEstimate() const { return m_lhsImpl.nonZerosEstimate() + m_rhsImpl.nonZerosEstimate(); }
661
662 protected:
663 const BinaryOp m_functor;
664 evaluator<LhsArg> m_lhsImpl;
665 evaluator<RhsArg> m_rhsImpl;
666};
667
668// "dense v sparse"
669template <typename XprType>
670struct sparse_disjunction_evaluator<XprType, IndexBased, IteratorBased> : evaluator_base<XprType> {
671 protected:
672 using BinaryOp = typename XprType::Functor;
673 using LhsArg = typename XprType::Lhs;
674 using RhsArg = typename XprType::Rhs;
675 using RhsIterator = typename evaluator<RhsArg>::InnerIterator;
676 using StorageIndex = typename XprType::StorageIndex;
677 using Scalar = typename traits<XprType>::Scalar;
678
679 public:
680 class InnerIterator {
681 enum { IsRowMajor = (int(RhsArg::Flags) & RowMajorBit) == RowMajorBit };
682
683 public:
684 EIGEN_STRONG_INLINE InnerIterator(const sparse_disjunction_evaluator& aEval, Index outer)
685 : m_lhsEval(aEval.m_lhsImpl),
686 m_rhsIter(aEval.m_rhsImpl, outer),
687 m_functor(aEval.m_functor),
688 m_value(0),
689 m_id(-1),
690 m_innerSize(aEval.m_expr.rhs().innerSize()) {
691 this->operator++();
692 }
693
694 EIGEN_STRONG_INLINE InnerIterator& operator++() {
695 ++m_id;
696 if (m_id < m_innerSize) {
697 Scalar lhsVal = m_lhsEval.coeff(IsRowMajor ? m_rhsIter.outer() : m_id, IsRowMajor ? m_id : m_rhsIter.outer());
698 if (m_rhsIter && m_rhsIter.index() == m_id) {
699 m_value = m_functor(lhsVal, m_rhsIter.value());
700 ++m_rhsIter;
701 } else
702 m_value = lhsVal;
703 }
704
705 return *this;
706 }
707
708 EIGEN_STRONG_INLINE Scalar value() const {
709 eigen_internal_assert(m_id < m_innerSize);
710 return m_value;
711 }
712
713 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
714 EIGEN_STRONG_INLINE Index outer() const { return m_rhsIter.outer(); }
715 EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_rhsIter.outer() : m_id; }
716 EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_rhsIter.outer(); }
717
718 EIGEN_STRONG_INLINE operator bool() const { return m_id < m_innerSize; }
719
720 protected:
721 const evaluator<LhsArg>& m_lhsEval;
722 RhsIterator m_rhsIter;
723 const BinaryOp& m_functor;
724 Scalar m_value;
725 StorageIndex m_id;
726 StorageIndex m_innerSize;
727 };
728
729 enum {
730 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
731 int(functor_traits<BinaryOp>::Cost),
732 Flags = XprType::Flags
733 };
734
735 explicit sparse_disjunction_evaluator(const XprType& xpr)
736 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_expr(xpr) {
737 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
738 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
739 }
740
741 inline Index nonZerosEstimate() const { return m_expr.size(); }
742
743 protected:
744 const BinaryOp m_functor;
745 evaluator<LhsArg> m_lhsImpl;
746 evaluator<RhsArg> m_rhsImpl;
747 const XprType& m_expr;
748};
749
750// "sparse v dense"
751template <typename XprType>
752struct sparse_disjunction_evaluator<XprType, IteratorBased, IndexBased> : evaluator_base<XprType> {
753 protected:
754 using BinaryOp = typename XprType::Functor;
755 using LhsArg = typename XprType::Lhs;
756 using RhsArg = typename XprType::Rhs;
757 using LhsIterator = typename evaluator<LhsArg>::InnerIterator;
758 using StorageIndex = typename XprType::StorageIndex;
759 using Scalar = typename traits<XprType>::Scalar;
760
761 public:
762 class InnerIterator {
763 enum { IsRowMajor = (int(LhsArg::Flags) & RowMajorBit) == RowMajorBit };
764
765 public:
766 EIGEN_STRONG_INLINE InnerIterator(const sparse_disjunction_evaluator& aEval, Index outer)
767 : m_lhsIter(aEval.m_lhsImpl, outer),
768 m_rhsEval(aEval.m_rhsImpl),
769 m_functor(aEval.m_functor),
770 m_value(0),
771 m_id(-1),
772 m_innerSize(aEval.m_expr.lhs().innerSize()) {
773 this->operator++();
774 }
775
776 EIGEN_STRONG_INLINE InnerIterator& operator++() {
777 ++m_id;
778 if (m_id < m_innerSize) {
779 Scalar rhsVal = m_rhsEval.coeff(IsRowMajor ? m_lhsIter.outer() : m_id, IsRowMajor ? m_id : m_lhsIter.outer());
780 if (m_lhsIter && m_lhsIter.index() == m_id) {
781 m_value = m_functor(m_lhsIter.value(), rhsVal);
782 ++m_lhsIter;
783 } else
784 m_value = rhsVal;
785 }
786
787 return *this;
788 }
789
790 EIGEN_STRONG_INLINE Scalar value() const {
791 eigen_internal_assert(m_id < m_innerSize);
792 return m_value;
793 }
794
795 EIGEN_STRONG_INLINE StorageIndex index() const { return m_id; }
796 EIGEN_STRONG_INLINE Index outer() const { return m_lhsIter.outer(); }
797 EIGEN_STRONG_INLINE Index row() const { return IsRowMajor ? m_lhsIter.outer() : m_id; }
798 EIGEN_STRONG_INLINE Index col() const { return IsRowMajor ? m_id : m_lhsIter.outer(); }
799
800 EIGEN_STRONG_INLINE operator bool() const { return m_id < m_innerSize; }
801
802 protected:
803 LhsIterator m_lhsIter;
804 const evaluator<RhsArg>& m_rhsEval;
805 const BinaryOp& m_functor;
806 Scalar m_value;
807 StorageIndex m_id;
808 StorageIndex m_innerSize;
809 };
810
811 enum {
812 CoeffReadCost = int(evaluator<LhsArg>::CoeffReadCost) + int(evaluator<RhsArg>::CoeffReadCost) +
813 int(functor_traits<BinaryOp>::Cost),
814 Flags = XprType::Flags
815 };
816
817 explicit sparse_disjunction_evaluator(const XprType& xpr)
818 : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()), m_expr(xpr) {
819 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
820 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
821 }
822
823 inline Index nonZerosEstimate() const { return m_expr.size(); }
824
825 protected:
826 const BinaryOp m_functor;
827 evaluator<LhsArg> m_lhsImpl;
828 evaluator<RhsArg> m_rhsImpl;
829 const XprType& m_expr;
830};
831
832// when DupFunc is wrapped with scalar_dup_op, use disjunction evaluator
833template <typename T1, typename T2, typename DupFunc, typename Lhs, typename Rhs>
834struct binary_evaluator<CwiseBinaryOp<scalar_disjunction_op<DupFunc, T1, T2>, Lhs, Rhs>, IteratorBased, IteratorBased>
835 : sparse_disjunction_evaluator<CwiseBinaryOp<scalar_disjunction_op<DupFunc, T1, T2>, Lhs, Rhs> > {
836 using XprType = CwiseBinaryOp<scalar_disjunction_op<DupFunc, T1, T2>, Lhs, Rhs>;
837 using Base = sparse_disjunction_evaluator<XprType>;
838 explicit binary_evaluator(const XprType& xpr) : Base(xpr) {}
839};
840} // namespace internal
841
842/***************************************************************************
843 * Implementation of SparseMatrixBase and SparseCwise functions/operators
844 ***************************************************************************/
845
846template <typename Derived>
847template <typename OtherDerived>
848Derived& SparseMatrixBase<Derived>::operator+=(const EigenBase<OtherDerived>& other) {
849 call_assignment(derived(), other.derived(), internal::add_assign_op<Scalar, typename OtherDerived::Scalar>());
850 return derived();
851}
852
853template <typename Derived>
854template <typename OtherDerived>
855Derived& SparseMatrixBase<Derived>::operator-=(const EigenBase<OtherDerived>& other) {
856 call_assignment(derived(), other.derived(), internal::sub_assign_op<Scalar, typename OtherDerived::Scalar>());
857 return derived();
858}
859
860template <typename Derived>
861template <typename OtherDerived>
862EIGEN_STRONG_INLINE Derived& SparseMatrixBase<Derived>::operator-=(const SparseMatrixBase<OtherDerived>& other) {
863 return derived() = derived() - other.derived();
864}
865
866template <typename Derived>
867template <typename OtherDerived>
868EIGEN_STRONG_INLINE Derived& SparseMatrixBase<Derived>::operator+=(const SparseMatrixBase<OtherDerived>& other) {
869 return derived() = derived() + other.derived();
870}
871
872template <typename Derived>
873template <typename OtherDerived>
874Derived& SparseMatrixBase<Derived>::operator+=(const DiagonalBase<OtherDerived>& other) {
875 call_assignment_no_alias(derived(), other.derived(),
876 internal::add_assign_op<Scalar, typename OtherDerived::Scalar>());
877 return derived();
878}
879
880template <typename Derived>
881template <typename OtherDerived>
882Derived& SparseMatrixBase<Derived>::operator-=(const DiagonalBase<OtherDerived>& other) {
883 call_assignment_no_alias(derived(), other.derived(),
884 internal::sub_assign_op<Scalar, typename OtherDerived::Scalar>());
885 return derived();
886}
887
888template <typename Derived>
889template <typename OtherDerived>
890EIGEN_STRONG_INLINE const typename SparseMatrixBase<Derived>::template CwiseProductDenseReturnType<OtherDerived>::Type
892 return typename CwiseProductDenseReturnType<OtherDerived>::Type(derived(), other.derived());
893}
894
895template <typename DenseDerived, typename SparseDerived>
896EIGEN_STRONG_INLINE const
898 const DenseDerived, const SparseDerived>
899 operator+(const MatrixBase<DenseDerived>& a, const SparseMatrixBase<SparseDerived>& b) {
901 const DenseDerived, const SparseDerived>(a.derived(), b.derived());
902}
903
904template <typename SparseDerived, typename DenseDerived>
905EIGEN_STRONG_INLINE const
907 const SparseDerived, const DenseDerived>
908 operator+(const SparseMatrixBase<SparseDerived>& a, const MatrixBase<DenseDerived>& b) {
910 const SparseDerived, const DenseDerived>(a.derived(), b.derived());
911}
912
913template <typename DenseDerived, typename SparseDerived>
914EIGEN_STRONG_INLINE const
916 const DenseDerived, const SparseDerived>
917 operator-(const MatrixBase<DenseDerived>& a, const SparseMatrixBase<SparseDerived>& b) {
919 const DenseDerived, const SparseDerived>(a.derived(), b.derived());
920}
921
922template <typename SparseDerived, typename DenseDerived>
923EIGEN_STRONG_INLINE const
925 const SparseDerived, const DenseDerived>
926 operator-(const SparseMatrixBase<SparseDerived>& a, const MatrixBase<DenseDerived>& b) {
928 const SparseDerived, const DenseDerived>(a.derived(), b.derived());
929}
930
931} // end namespace Eigen
932
933#endif // EIGEN_SPARSE_CWISE_BINARY_OP_H
Generic expression where a coefficient-wise binary operator is applied to two expressions.
Definition CwiseBinaryOp.h:80
Base class for diagonal matrices and expressions.
Definition DiagonalMatrix.h:34
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
Base class of any sparse matrices or sparse expressions.
Definition SparseMatrixBase.h:31
constexpr const CwiseBinaryOp< internal::scalar_product_op< Derived ::Scalar, OtherDerived ::Scalar >, const Derived, const OtherDerived > cwiseProduct(const Eigen::SparseMatrixBase< OtherDerived > &other) const
Definition SparseMatrixBase.h:25
constexpr unsigned int RowMajorBit
Definition Constants.h:71
Definition EigenBase.h:34
Definition Constants.h:545