This bugzilla service is closed. All entries have been migrated to https://gitlab.com/libeigen/eigen
Bug 1585 - Matrix product is repeatedly evaluated when iterating over the product expression
Summary: Matrix product is repeatedly evaluated when iterating over the product expres...
Status: RESOLVED FIXED
Alias: None
Product: Eigen
Classification: Unclassified
Component: Core - expression templates (show other bugs)
Version: 3.3 (current stable)
Hardware: All All
: Normal Documentation
Assignee: Nobody
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 3.3 3.4
  Show dependency treegraph
 
Reported: 2018-08-16 02:49 UTC by taroxd
Modified: 2019-12-04 17:51 UTC (History)
4 users (show)



Attachments

Description taroxd 2018-08-16 02:49:43 UTC
Here is the code that causes the problem.

#include <chrono>
#include <Eigen/Eigen>
#include <iostream>

template <typename Derived>
void my_print_mat1(const MatrixBase<Derived>& v_) {
    volatile double dummy_output;
    const Derived& v = v_.derived();
    auto tstart = Clock::now();

    auto size = v.size();

    for (auto i = 0; i < size; ++i) {
        dummy_output = v(i);
    }

    std::chrono::duration<double> time = Clock::now() - tstart;
    std::cout << "my_print_mat1: " << time.count() << '\n';
}

void my_print_mat2(const Ref<const Vec>& v) {
    volatile double dummy_output;
    auto tstart = Clock::now();

    auto size = v.size();

    for (auto i = 0; i < size; ++i) {
        dummy_output = v(i);
    }

    std::chrono::duration<double> time = Clock::now() - tstart;

    std::cout << "my_print_mat2: " << time.count() << '\n';
}


int main() {
    constexpr int size = 1000;
    Mat mat = Mat::Random(size, size);
    Vec vec = Vec::Random(size);
    my_print_mat1(mat * vec);
    my_print_mat2(mat * vec);
}


On my PC, the output is:
my_print_mat1: 0.97757
my_print_mat2: 2.3e-06

It appears that, in function "my_print_mat1", matrix-vector product is evaluated every time when the i-th component of v is accessed.

However, according to the documentation, my_print_mat1 is the recommended way to write functions that take Eigen types as parameters. (https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html)

And in this topic (https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html), I am told that matrix product expression will be evaluated in to a temporary variable. "Again, the most important example of such an expression is the matrix product expression." The code example above seems to contradict what the documatation claimed.

When I write a function that takes Eigen types as parameters, how could I get all the good of avoiding a temporary while making sure that costly expressions (like matrix product) are not repeatedly evaluated when iterating through a vector?

Note: In my project, the function is not as simple as printing a vector. And the iteration through every component of a vector is unavoidable.
Comment 1 Gael Guennebaud 2018-08-16 12:02:54 UTC
This is actually a documentation issue, the page TopicLazyEvaluation has not been properly updated changes introduced in 3.3.


Regarding:

> how could I get all the good of avoiding a temporary while making sure that costly expressions are not repeatedly evaluated?

that's a very good question and unfortunately we never converged to a simple public API for that, mostly because the ideal answer depends a lot on how the expression/matrix is going to be used. In many cases, Ref<> is just fine, but internally we have internal::nested_eval<XprType,EvalCount>::type that give you either XprType& or the return type of XprType::eval() depending on the number of time (EvalCount) the expression will be accessed, e.g.:

template<typename XprType>
void foo(const MatrixBase<XprType>& xpr_base) {
  typedef typename internal::nested_eval<XprType,2>::type NestedType;
  NestedType xpr(xpr_base.derived());

  ...
}

You can pass Dynamic to EvalCount to say "a lot", though currently any EvalCount in [3..infinity] will give you the same answer.
Comment 2 Gael Guennebaud 2019-01-16 15:30:14 UTC
I updated the respective doc page.

https://bitbucket.org/eigen/eigen/commits/04dd8265a4e6/
Comment 3 Nobody 2019-12-04 17:51:42 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to gitlab.com's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.com/libeigen/eigen/issues/1585.

Note You need to log in before you can comment on or make changes to this bug.