Loading...
Searching...
No Matches
mykroneckerproduct.C
Go to the documentation of this file.
1/*
2 * This file is part of the SPLINTER library.
3 * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com).
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8*/
9
10#include "mykroneckerproduct.h"
11#include <unsupported/Eigen/KroneckerProduct>
12
13namespace SPLINTER
14{
15
16/*
17 * Implementation of Kronecker product.
18 * Eigen has an implementation of the Kronecker product,
19 * but it is very slow due to poor memory reservation.
20 * See: https://forum.kde.org/viewtopic.php?f=74&t=106955&p=309990&hilit=kronecker#p309990
21 * When Eigen update their implementation, and officially support it, we switch to that.
22 */
23SparseMatrix myKroneckerProduct(const SparseMatrix& A, const SparseMatrix& B)
24{
25 SparseMatrix AB(A.rows()*B.rows(), A.cols()*B.cols());
26 // Reserve memory for AB
27 //AB.reserve(A.nonZeros()*B.nonZeros()); // Does not reserve inner vectors (slow)
28 //int innernnz = std::ceil(A.nonZeros()*B.nonZeros()/AB.outerSize());
29 //AB.reserve(Eigen::VectorXi::Constant(AB.outerSize(), innernnz)); // Assumes equal distribution of non-zeros (slow)
30 // Calculate exact number of non-zeros for each inner vector
31 Eigen::VectorXi nnzA = Eigen::VectorXi::Zero(A.outerSize());
32 Eigen::VectorXi nnzB = Eigen::VectorXi::Zero(B.outerSize());
33 Eigen::VectorXi nnzAB = Eigen::VectorXi::Zero(AB.outerSize());
34 //innerNonZeros.setZero();
35
36 for (int jA = 0; jA < A.outerSize(); ++jA)
37 {
38 int nnz = 0;
39
40 for (SparseMatrix::InnerIterator itA(A, jA); itA; ++itA)
41 {
42 nnz++;
43 }
44
45 nnzA(jA) = nnz;
46 }
47
48 for (int jB = 0; jB < B.outerSize(); ++jB)
49 {
50 int nnz = 0;
51
52 for (SparseMatrix::InnerIterator itB(B, jB); itB; ++itB)
53 {
54 nnz++;
55 }
56
57 nnzB(jB) = nnz;
58 }
59
60 int innz = 0;
61
62 for (int i = 0; i < nnzA.rows(); ++i)
63 {
64 for (int j = 0; j < nnzB.rows(); ++j)
65 {
66 nnzAB(innz) = nnzA(i) * nnzB(j);
67 innz++;
68 }
69 }
70
71 AB.reserve(nnzAB);
72 // Non-zero tolerance
73 double tolerance = std::numeric_limits<SparseMatrix::Scalar>::epsilon();
74
75 // Compute Kronecker product
76 for (int jA = 0; jA < A.outerSize(); ++jA)
77 {
78 for (SparseMatrix::InnerIterator itA(A, jA); itA; ++itA)
79 {
80 if (std::abs(itA.value()) > tolerance)
81 {
82 int jrow = itA.row() * B.rows();
83 int jcol = itA.col() * B.cols();
84
85 for (int jB = 0; jB < B.outerSize(); ++jB)
86 {
87 for (SparseMatrix::InnerIterator itB(B, jB); itB; ++itB)
88 {
89 if (std::abs(itA.value()*itB.value()) > tolerance)
90 {
91 int row = jrow + itB.row();
92 int col = jcol + itB.col();
93 AB.insert(row, col) = itA.value() * itB.value();
94 }
95 }
96 }
97 }
98 }
99 }
100
101 AB.makeCompressed();
102 return AB;
103}
104
105SparseVector kroneckerProductVectors(const std::vector<SparseVector>& vectors)
106{
107 // Create two temp matrices
108 SparseMatrix temp1(1, 1);
109 temp1.insert(0, 0) = 1;
110 SparseMatrix temp2 = temp1;
111 // Multiply from left
112 int counter = 0;
113
114 for (const auto& vec : vectors)
115 {
116 // Avoid copy
117 if (counter % 2 == 0)
118 {
119 temp1 = kroneckerProduct(temp2, vec);
120 }
121 else
122 {
123 temp2 = kroneckerProduct(temp1, vec);
124 }
125
126 ++counter;
127 }
128
129 // Return correct product
130 if (counter % 2 == 0)
131 {
132 return temp2;
133 }
134
135 return temp1;
136}
137
138DenseVector kroneckerProductVectors(const std::vector<DenseVector>& vectors)
139{
140 // Create two temp matrices
141 DenseVector temp1(1);
142 temp1(0) = 1;
143 DenseVector temp2 = temp1;
144 // Multiply from left
145 int counter = 0;
146
147 for (const auto& vec : vectors)
148 {
149 // Avoid copy
150 if (counter % 2 == 0)
151 {
152 temp1 = kroneckerProduct(temp2, vec);
153 }
154 else
155 {
156 temp2 = kroneckerProduct(temp1, vec);
157 }
158
159 ++counter;
160 }
161
162 // Return correct product
163 if (counter % 2 == 0)
164 {
165 return temp2;
166 }
167
168 return temp1;
169}
170
171SparseMatrix kroneckerProductMatrices(const std::vector<SparseMatrix>& matrices)
172{
173 // Create two temp matrices
174 SparseMatrix temp1(1, 1);
175 temp1.insert(0, 0) = 1;
176 SparseMatrix temp2 = temp1;
177 // Multiply from left
178 int counter = 0;
179
180 for (const auto& mat : matrices)
181 {
182 // Avoid copy
183 if (counter % 2 == 0)
184 {
185 temp1 = kroneckerProduct(temp2, mat);
186 }
187 else
188 {
189 temp2 = kroneckerProduct(temp1, mat);
190 }
191
192 ++counter;
193 }
194
195 // Return correct product
196 if (counter % 2 == 0)
197 {
198 return temp2;
199 }
200
201 return temp1;
202}
203
204} // namespace SPLINTER
volScalarField & A
SparseMatrix kroneckerProductMatrices(const std::vector< SparseMatrix > &matrices)
SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B)
SparseVector kroneckerProductVectors(const std::vector< SparseVector > &vectors)
singVal col(i)
label i
Definition pEqn.H:46