Medial Code Documentation
Loading...
Searching...
No Matches
ConservativeSparseSparseProduct.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008-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
10#ifndef EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H
11#define EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H
12
13namespace Eigen {
14
15namespace internal {
16
17template<typename Lhs, typename Rhs, typename ResultType>
18static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, bool sortedInsertion = false)
19{
20 typedef typename remove_all<Lhs>::type::Scalar Scalar;
21
22 // make sure to call innerSize/outerSize since we fake the storage order.
23 Index rows = lhs.innerSize();
24 Index cols = rhs.outerSize();
25 eigen_assert(lhs.outerSize() == rhs.innerSize());
26
27 ei_declare_aligned_stack_constructed_variable(bool, mask, rows, 0);
28 ei_declare_aligned_stack_constructed_variable(Scalar, values, rows, 0);
29 ei_declare_aligned_stack_constructed_variable(Index, indices, rows, 0);
30
31 std::memset(mask,0,sizeof(bool)*rows);
32
33 evaluator<Lhs> lhsEval(lhs);
34 evaluator<Rhs> rhsEval(rhs);
35
36 // estimate the number of non zero entries
37 // given a rhs column containing Y non zeros, we assume that the respective Y columns
38 // of the lhs differs in average of one non zeros, thus the number of non zeros for
39 // the product of a rhs column with the lhs is X+Y where X is the average number of non zero
40 // per column of the lhs.
41 // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs)
42 Index estimated_nnz_prod = lhsEval.nonZerosEstimate() + rhsEval.nonZerosEstimate();
43
44 res.setZero();
45 res.reserve(Index(estimated_nnz_prod));
46 // we compute each column of the result, one after the other
47 for (Index j=0; j<cols; ++j)
48 {
49
50 res.startVec(j);
51 Index nnz = 0;
52 for (typename evaluator<Rhs>::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt)
53 {
54 Scalar y = rhsIt.value();
55 Index k = rhsIt.index();
56 for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt)
57 {
58 Index i = lhsIt.index();
59 Scalar x = lhsIt.value();
60 if(!mask[i])
61 {
62 mask[i] = true;
63 values[i] = x * y;
64 indices[nnz] = i;
65 ++nnz;
66 }
67 else
68 values[i] += x * y;
69 }
70 }
71 if(!sortedInsertion)
72 {
73 // unordered insertion
74 for(Index k=0; k<nnz; ++k)
75 {
76 Index i = indices[k];
77 res.insertBackByOuterInnerUnordered(j,i) = values[i];
78 mask[i] = false;
79 }
80 }
81 else
82 {
83 // alternative ordered insertion code:
84 const Index t200 = rows/11; // 11 == (log2(200)*1.39)
85 const Index t = (rows*100)/139;
86
87 // FIXME reserve nnz non zeros
88 // FIXME implement faster sorting algorithms for very small nnz
89 // if the result is sparse enough => use a quick sort
90 // otherwise => loop through the entire vector
91 // In order to avoid to perform an expensive log2 when the
92 // result is clearly very sparse we use a linear bound up to 200.
93 if((nnz<200 && nnz<t200) || nnz * numext::log2(int(nnz)) < t)
94 {
95 if(nnz>1) std::sort(indices,indices+nnz);
96 for(Index k=0; k<nnz; ++k)
97 {
98 Index i = indices[k];
99 res.insertBackByOuterInner(j,i) = values[i];
100 mask[i] = false;
101 }
102 }
103 else
104 {
105 // dense path
106 for(Index i=0; i<rows; ++i)
107 {
108 if(mask[i])
109 {
110 mask[i] = false;
111 res.insertBackByOuterInner(j,i) = values[i];
112 }
113 }
114 }
115 }
116 }
117 res.finalize();
118}
119
120
121} // end namespace internal
122
123namespace internal {
124
125template<typename Lhs, typename Rhs, typename ResultType,
126 int LhsStorageOrder = (traits<Lhs>::Flags&RowMajorBit) ? RowMajor : ColMajor,
127 int RhsStorageOrder = (traits<Rhs>::Flags&RowMajorBit) ? RowMajor : ColMajor,
128 int ResStorageOrder = (traits<ResultType>::Flags&RowMajorBit) ? RowMajor : ColMajor>
130
131template<typename Lhs, typename Rhs, typename ResultType>
133{
134 typedef typename remove_all<Lhs>::type LhsCleaned;
135 typedef typename LhsCleaned::Scalar Scalar;
136
137 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
138 {
142
143 // If the result is tall and thin (in the extreme case a column vector)
144 // then it is faster to sort the coefficients inplace instead of transposing twice.
145 // FIXME, the following heuristic is probably not very good.
146 if(lhs.rows()>=rhs.cols())
147 {
148 ColMajorMatrix resCol(lhs.rows(),rhs.cols());
149 // perform sorted insertion
150 internal::conservative_sparse_sparse_product_impl<Lhs,Rhs,ColMajorMatrix>(lhs, rhs, resCol, true);
151 res = resCol.markAsRValue();
152 }
153 else
154 {
155 ColMajorMatrixAux resCol(lhs.rows(),rhs.cols());
156 // ressort to transpose to sort the entries
157 internal::conservative_sparse_sparse_product_impl<Lhs,Rhs,ColMajorMatrixAux>(lhs, rhs, resCol, false);
159 res = resRow.markAsRValue();
160 }
161 }
162};
163
164template<typename Lhs, typename Rhs, typename ResultType>
166{
167 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
168 {
171 RowMajorMatrix resRow(lhs.rows(), rhs.cols());
172 internal::conservative_sparse_sparse_product_impl<RowMajorMatrix,Lhs,RowMajorMatrix>(rhsRow, lhs, resRow);
173 res = resRow;
174 }
175};
176
177template<typename Lhs, typename Rhs, typename ResultType>
179{
180 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
181 {
184 RowMajorMatrix resRow(lhs.rows(), rhs.cols());
185 internal::conservative_sparse_sparse_product_impl<Rhs,RowMajorMatrix,RowMajorMatrix>(rhs, lhsRow, resRow);
186 res = resRow;
187 }
188};
189
190template<typename Lhs, typename Rhs, typename ResultType>
192{
193 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
194 {
196 RowMajorMatrix resRow(lhs.rows(), rhs.cols());
197 internal::conservative_sparse_sparse_product_impl<Rhs,Lhs,RowMajorMatrix>(rhs, lhs, resRow);
198 res = resRow;
199 }
200};
201
202
203template<typename Lhs, typename Rhs, typename ResultType>
205{
206 typedef typename traits<typename remove_all<Lhs>::type>::Scalar Scalar;
207
208 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
209 {
211 ColMajorMatrix resCol(lhs.rows(), rhs.cols());
212 internal::conservative_sparse_sparse_product_impl<Lhs,Rhs,ColMajorMatrix>(lhs, rhs, resCol);
213 res = resCol;
214 }
215};
216
217template<typename Lhs, typename Rhs, typename ResultType>
219{
220 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
221 {
224 ColMajorMatrix resCol(lhs.rows(), rhs.cols());
225 internal::conservative_sparse_sparse_product_impl<ColMajorMatrix,Rhs,ColMajorMatrix>(lhsCol, rhs, resCol);
226 res = resCol;
227 }
228};
229
230template<typename Lhs, typename Rhs, typename ResultType>
232{
233 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
234 {
237 ColMajorMatrix resCol(lhs.rows(), rhs.cols());
238 internal::conservative_sparse_sparse_product_impl<Lhs,ColMajorMatrix,ColMajorMatrix>(lhs, rhsCol, resCol);
239 res = resCol;
240 }
241};
242
243template<typename Lhs, typename Rhs, typename ResultType>
245{
246 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
247 {
250 RowMajorMatrix resRow(lhs.rows(),rhs.cols());
251 internal::conservative_sparse_sparse_product_impl<Rhs,Lhs,RowMajorMatrix>(rhs, lhs, resRow);
252 // sort the non zeros:
254 res = resCol;
255 }
256};
257
258} // end namespace internal
259
260
261namespace internal {
262
263template<typename Lhs, typename Rhs, typename ResultType>
264static void sparse_sparse_to_dense_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res)
265{
266 typedef typename remove_all<Lhs>::type::Scalar Scalar;
267 Index cols = rhs.outerSize();
268 eigen_assert(lhs.outerSize() == rhs.innerSize());
269
272
273 for (Index j=0; j<cols; ++j)
274 {
275 for (typename evaluator<Rhs>::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt)
276 {
277 Scalar y = rhsIt.value();
278 Index k = rhsIt.index();
279 for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, k); lhsIt; ++lhsIt)
280 {
281 Index i = lhsIt.index();
282 Scalar x = lhsIt.value();
283 res.coeffRef(i,j) += x * y;
284 }
285 }
286 }
287}
288
289
290} // end namespace internal
291
292namespace internal {
293
294template<typename Lhs, typename Rhs, typename ResultType,
295 int LhsStorageOrder = (traits<Lhs>::Flags&RowMajorBit) ? RowMajor : ColMajor,
296 int RhsStorageOrder = (traits<Rhs>::Flags&RowMajorBit) ? RowMajor : ColMajor>
298
299template<typename Lhs, typename Rhs, typename ResultType>
301{
302 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
303 {
304 internal::sparse_sparse_to_dense_product_impl<Lhs,Rhs,ResultType>(lhs, rhs, res);
305 }
306};
307
308template<typename Lhs, typename Rhs, typename ResultType>
310{
311 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
312 {
315 internal::sparse_sparse_to_dense_product_impl<ColMajorMatrix,Rhs,ResultType>(lhsCol, rhs, res);
316 }
317};
318
319template<typename Lhs, typename Rhs, typename ResultType>
321{
322 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
323 {
326 internal::sparse_sparse_to_dense_product_impl<Lhs,ColMajorMatrix,ResultType>(lhs, rhsCol, res);
327 }
328};
329
330template<typename Lhs, typename Rhs, typename ResultType>
332{
333 static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res)
334 {
336 internal::sparse_sparse_to_dense_product_impl<Rhs,Lhs,Transpose<ResultType> >(rhs, lhs, trRes);
337 }
338};
339
340
341} // end namespace internal
342
343} // end namespace Eigen
344
345#endif // EIGEN_CONSERVATIVESPARSESPARSEPRODUCT_H
Pseudo expression representing a solving operation.
Definition Solve.h:63
@ ColMajor
Storage order is column major (see TopicStorageOrders).
Definition Constants.h:320
@ RowMajor
Storage order is row major (see TopicStorageOrders).
Definition Constants.h:322
const unsigned int RowMajorBit
for a matrix, this means that the storage order is row-major.
Definition Constants.h:61
Definition ConservativeSparseSparseProduct.h:129
Definition ConservativeSparseSparseProduct.h:297