Re: [eigen] The "nested" concept |

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]

*To*: eigen@xxxxxxxxxxxxxxxxxxx*Subject*: Re: [eigen] The "nested" concept*From*: Thomas Capricelli <orzel@xxxxxxxxxxxxxxx>*Date*: Wed, 30 Jun 2010 05:31:32 +0200*Organization*: freehackers.org

Guys! This was very interesting. Typically the kind of thing I would see fit in the 'developers' documentation'! Thomas -- Thomas Capricelli <orzel@xxxxxxxxxxxxxxx> http://www.freehackers.org/thomas In data martedì 29 giugno 2010 23:27:45, Gael Guennebaud ha scritto: > Hi, > > let's pick a simple example: > > MatrixXf A, B, C; > C = A.transpose() + B; > > here A.transpose() returns an object of type: > > Transpose<MatrixXf> > > where the MatrixXf A is nested into the Transpose expression. The > nested type tells how to store the nested object. Here > MatrixXf::Nested boils down to a MatrixXf&, and thus "A.transpose()" > stores a reference to A. > > Now, you might wonder why we introduced such a nesting type mechanism > and not always use a reference. There are two main reasons: > > 1 - Unlike Matrix or Array, other expressions are lightweight and > better nested by value. In the previous example, "A.transpose() + B" > returns an object of type CwiseBinaryOp<ei_scalar_sum_op<float>, > Transpose<MatrixXf>, MatrixXf> storing both sides of the addition as > follow: > > Transpose<MatrixXf>::Nested lhs; // left hand side > MatrixXf::Nested rhs; // right hand side > > which boils down to: > > const Transpose<MatrixXf> lhs; // nesting by value > const MatrixXf& rhs; // nesting by reference > > Nesting by value small object avoids temporary headache when a > function has to return complex expressions, e.g.: > > template<typename A, typename B> > CwiseBinaryOp<ei_scalar_sum_op<float>, Transpose<A>, B> adjoint(const > A& a, const B& b) > { > return a.transpose() + b; > } > > If the temporary "a.transpose()" was stored by reference by the > CwiseBinaryOp expression, then you would end up with a segfault > because the "a.transpose()" temporary is destroyed just before the > function returns, and so the CwiseBinaryOp expression would store a > reference to dead object... > > 2 - Another reason is to allow to handle expressions which has to be > evaluated into a temporary before being used. For instance, in the > following example: > > d = a * b + c; > > for performance reason, the matrix product a * b has to be evaluated > into a temporary before evaluating the addition. This is achieved as > follow. Here we build the expression of type: > > CwiseBinaryOp<ei_scalar_sum_op<float>, Product<MatrixXf,MatrixXf>, MatrixXf> > > which stores a Product<MatrixXf,MatrixXf>::Nested for the lhs, and > Product<MatrixXf,MatrixXf>::Nested is ... MatrixXf !! > > Something more complicated: > > (a + b) * c > > Here, if c is not too small, it is better to evaluate (a+b) into a > temporary before doing the matrix product, otherwise, a+b would be > computed c.cols() times... To this end we have a ei_nested<> helper > class to determine the ideal nesting type. In Product, we have > something like: > > ei_nested<CwiseBinaryOp<ei_scalar_sum_op<float>, type_of_a, > type_of_b>, type_of_c::ColsAtCompileTime>::type > > giving us the nesting type of the left hand side of the product (here > a MatrixXf if a, b, and c are MatrixXf). For the right hand side here > we have: > > ei_nested<CwiseBinaryOp<ei_scalar_sum_op<float>, type_of_c, > type_of_a_plus_b::RowsAtCompileTime>::type > > which gives us a MatrixXf&. > > ei_nested<> determines whether the nested expression has to be > evaluated or not in function of an estimation of the evaluation cost > of one coefficient. This cost is automatically computed by the > expressions in the ei_traits<> specializations. > > Yes, this is a bit complicated, but what is very important here, and > that we have to better document, is that when you write a generic > function taking, e.g., a MatrixBase<Derived> object you should really > honor the nesting type of the Derived class: > > template<typename Derived> > void foo(const MatrixBase<Derived>& _x) > { > typename Derived::Nested x(_x.derived()); > > // use x safely > } > > Actually, is you use the argument more than once, you should even use > the ei_nested<> helper: > > template<typename Derived> > typename Derived::Scalar foo(const MatrixBase<Derived>& _x) > { > typename ei_nested<Derived,2>::type x(_x.derived()); > > return (x + x.adjoint()).maxCoeff(); > } > > if you don't do so, and call: > > foo(a*b); > > then the expensive product a*b will be computed twice !! > > gael > > On Tue, Jun 29, 2010 at 9:29 PM, Manoj Rajagopalan <rmanoj@xxxxxxxxx> wrote: > > Hi, > > > > I see typedefs with names like "MatrixTypeNested". What is this nesting > > concept? > > > > thanks, > > Manoj > > > > > > > > >

**Follow-Ups**:**Re: [eigen] The "nested" concept***From:*Benoit Jacob

**Re: [eigen] The "nested" concept***From:*Manoj Rajagopalan

**References**:**[eigen] The "nested" concept***From:*Manoj Rajagopalan

**Re: [eigen] The "nested" concept***From:*Gael Guennebaud

**Messages sorted by:**[ date | thread ]- Prev by Date:
**[eigen] beta1 process** - Next by Date:
**[eigen] Question about the class hierarchy** - Previous by thread:
**Re: [eigen] The "nested" concept** - Next by thread:
**Re: [eigen] The "nested" concept**

Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |