New user self-registration is disabled due to spam. Please email eigen-core-team @ lists.tuxfamily.org if you need an account.
Before reporting a bug, please make sure that your Eigen version is up-to-date!
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-01-16 15:30 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/

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