KroneckerTensorProduct.h revision c981c48f5bc9aefeffc0bcb0cc3934c2fae179dd
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2011 Kolja Brix <brix@igpm.rwth-aachen.de>
5// Copyright (C) 2011 Andreas Platen <andiplaten@gmx.de>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11
12#ifndef KRONECKER_TENSOR_PRODUCT_H
13#define KRONECKER_TENSOR_PRODUCT_H
14
15
16namespace Eigen {
17
18namespace internal {
19
20/*!
21 * Kronecker tensor product helper function for dense matrices
22 *
23 * \param A   Dense matrix A
24 * \param B   Dense matrix B
25 * \param AB_ Kronecker tensor product of A and B
26 */
27template<typename Derived_A, typename Derived_B, typename Derived_AB>
28void kroneckerProduct_full(const Derived_A& A, const Derived_B& B, Derived_AB & AB)
29{
30  const unsigned int Ar = A.rows(),
31                     Ac = A.cols(),
32                     Br = B.rows(),
33                     Bc = B.cols();
34  for (unsigned int i=0; i<Ar; ++i)
35    for (unsigned int j=0; j<Ac; ++j)
36      AB.block(i*Br,j*Bc,Br,Bc) = A(i,j)*B;
37}
38
39
40/*!
41 * Kronecker tensor product helper function for matrices, where at least one is sparse
42 *
43 * \param A   Matrix A
44 * \param B   Matrix B
45 * \param AB_ Kronecker tensor product of A and B
46 */
47template<typename Derived_A, typename Derived_B, typename Derived_AB>
48void kroneckerProduct_sparse(const Derived_A &A, const Derived_B &B, Derived_AB &AB)
49{
50  const unsigned int Ar = A.rows(),
51                     Ac = A.cols(),
52                     Br = B.rows(),
53                     Bc = B.cols();
54  AB.resize(Ar*Br,Ac*Bc);
55  AB.resizeNonZeros(0);
56  AB.reserve(A.nonZeros()*B.nonZeros());
57
58  for (int kA=0; kA<A.outerSize(); ++kA)
59  {
60    for (int kB=0; kB<B.outerSize(); ++kB)
61    {
62      for (typename Derived_A::InnerIterator itA(A,kA); itA; ++itA)
63      {
64        for (typename Derived_B::InnerIterator itB(B,kB); itB; ++itB)
65        {
66          const unsigned int iA = itA.row(),
67                             jA = itA.col(),
68                             iB = itB.row(),
69                             jB = itB.col(),
70                             i  = iA*Br + iB,
71                             j  = jA*Bc + jB;
72          AB.insert(i,j) = itA.value() * itB.value();
73        }
74      }
75    }
76  }
77}
78
79} // end namespace internal
80
81
82
83/*!
84 * Computes Kronecker tensor product of two dense matrices
85 *
86 * \param a  Dense matrix a
87 * \param b  Dense matrix b
88 * \param c  Kronecker tensor product of a and b
89 */
90template<typename A,typename B,typename CScalar,int CRows,int CCols, int COptions, int CMaxRows, int CMaxCols>
91void kroneckerProduct(const MatrixBase<A>& a, const MatrixBase<B>& b, Matrix<CScalar,CRows,CCols,COptions,CMaxRows,CMaxCols>& c)
92{
93  c.resize(a.rows()*b.rows(),a.cols()*b.cols());
94  internal::kroneckerProduct_full(a.derived(), b.derived(), c);
95}
96
97/*!
98 * Computes Kronecker tensor product of two dense matrices
99 *
100 * Remark: this function uses the const cast hack and has been
101 *         implemented to make the function call possible, where the
102 *         output matrix is a submatrix, e.g.
103 *           kroneckerProduct(A,B,AB.block(2,5,6,6));
104 *
105 * \param a  Dense matrix a
106 * \param b  Dense matrix b
107 * \param c  Kronecker tensor product of a and b
108 */
109template<typename A,typename B,typename C>
110void kroneckerProduct(const MatrixBase<A>& a, const MatrixBase<B>& b, MatrixBase<C> const & c_)
111{
112  MatrixBase<C>& c = const_cast<MatrixBase<C>& >(c_);
113  internal::kroneckerProduct_full(a.derived(), b.derived(), c.derived());
114}
115
116/*!
117 * Computes Kronecker tensor product of a dense and a sparse matrix
118 *
119 * \param a  Dense matrix a
120 * \param b  Sparse matrix b
121 * \param c  Kronecker tensor product of a and b
122 */
123template<typename A,typename B,typename C>
124void kroneckerProduct(const MatrixBase<A>& a, const SparseMatrixBase<B>& b, SparseMatrixBase<C>& c)
125{
126  internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
127}
128
129/*!
130 * Computes Kronecker tensor product of a sparse and a dense matrix
131 *
132 * \param a  Sparse matrix a
133 * \param b  Dense matrix b
134 * \param c  Kronecker tensor product of a and b
135 */
136template<typename A,typename B,typename C>
137void kroneckerProduct(const SparseMatrixBase<A>& a, const MatrixBase<B>& b, SparseMatrixBase<C>& c)
138{
139  internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
140}
141
142/*!
143 * Computes Kronecker tensor product of two sparse matrices
144 *
145 * \param a  Sparse matrix a
146 * \param b  Sparse matrix b
147 * \param c  Kronecker tensor product of a and b
148 */
149template<typename A,typename B,typename C>
150void kroneckerProduct(const SparseMatrixBase<A>& a, const SparseMatrixBase<B>& b, SparseMatrixBase<C>& c)
151{
152  internal::kroneckerProduct_sparse(a.derived(), b.derived(), c.derived());
153}
154
155} // end namespace Eigen
156
157#endif // KRONECKER_TENSOR_PRODUCT_H
158