Reputation: 3352
Using the Eigen C++ Matrix library, how can one efficiently multiply an n x n matrix A with a n x m matrix B and store the result in A? That is, how can I avoid generating a temporary n x m matrix and instead store the result directly in B?
For applications where m is very much larger (e.g. 100000) than n (e.g. 3), this definitely makes sense since it avoids the application of very a large array.
The following code, I cannot get to work:
B.noalias() = A * B;
I would think, that what would have to happen internally is
the following. Each column of B should be treated separately.
The column under consideration column_i
must be copied to a backup
column column_tmp
. Then,
B(row_i, column_i) = A.row(row_i) * column_tmp; // dot-product
for all column_i
= 0 to m. Is there a way in Eigen to do this
efficiently and profit from its optimizations?
Upvotes: 2
Views: 4063
Reputation: 29205
Yes with a 3x3 times 3xHuge your column-by-column evaluation would indeed make sense, but not in the general case. For instance, if n=m=1000, then the column-by-column evaluation would be orders of magnitude slower than the current Eigen logic.
If you write:
B.noalias() = A * B;
Eigen will follow a col-by-col evaluation (because A is small at compile-time), but the result will be wrong because B does alias, basically it will generate:
for j = 0..m-1
B.col(j).noalias() = A * B.col(j);
To solve this issue elegantly we would need a way to say that only different columns do not alias... The proposed:
B.transpose() *= A.transpose();
is indeed an option let Eigen knows at compile time this kind of information, though having to transpose both sides is a bit cumbersome. And the proper evaluation logic still needs to be implemented on Eigen's side. Currently this information is not exploited.
Upvotes: 2
Reputation: 5624
The most explicit way of telling Eigen that you want the product to happen "in place" could be:
B.transpose() *= A.transpose();
// or B.applyOnTheLeft(A);
that said, there's no guarantee this won't incur in any temporary, you'll have to trust internal Eigen cost logic for that (Eigen designers probably know better :) ... or check it yourself via a debugger, after proper profiling suggested this to be a real problem and not just premature optimization).
On my Eigen copy (3.2.7), the above invokes MatrixBase::applyThisOnTheRight
directly on the Transpose
expression, that in turn sadly reduces to B=A*B
internally; the same happens as of applyOnTheLeft
, so you're out of luck in this case.
If you really need to avoid any nxm temporary, you can perform the product manually vector-wise, something like:
for(auto i=0;i<B.cols();++i)
B.col(i) = A * B.col(i);
this will consume much less extra memory assuming B.rows()
<<B.cols()
,
but you may miss some important optimizations here; indeed, I guess having a temporary could still give the best trade-off here.
Upvotes: 5
Reputation: 62576
Your example of B.noalias() = A * B;
does not match "store the result in A". All you need for that is A *= B;
. If you instead do intend to overwrite B
, then you are lying with .noalias()
Upvotes: 1