On 10/8/12 4:27 AM, Ben Goodrich wrote:
> On Friday, October 5, 2012 6:21:17 PM UTC-4, Ben Goodrich wrote:
> So, if it is the case that ||b.cast<var>()|| does not make a temporary, as suggested by the (rather minimal)
> documentation at
>
>
http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a660200abaf1fc4b888330a37d6132b76
> which does say that the result is an expression, then do we really need so much specialized promotion / to_var()
> business that interferes with writing regular Eigen code?
From what I can tell from a brief dip into the Eigen
code, the doc's right -- it creates a templated view of
the underlying matrix.
The problem is later, when you access elements. There
they'll get cast on an access-by-access basis, which is
even worse! This creates a new auto-dif var on the stack
for every access, not just for every double matrix.
Finally, what we really need is to create our own
expression templates that would use implementations of
the basic multiply, etc. ops like the ones Marcus has
coded in stan/agrad/matrix.
> Is the answer that the above wastes a small amount of time
> calculating dc/db00 and dc/db10 and if so, can we do something about that? Or is the answer that we would have to write
> an equally frustrating amount of code in order to test whether we need to do a .cast<var>() ?
> I assume (perhaps wrongly)
> that if b were already a Matrix<var,Dynamic,Dynamic> then ||b.cast<var>() ||would be a no-op, so can we just cast
> everywhere but the double op double case?
That should be right -- casts of type T to type T
should be compilable away because the types of everything
are known at compile time. But see above.
Overall, what I think we need to do is either
A) upgrade all their unary trait specifications to
ternary (operand1, operand2, result),
OR
B) follow their complex implementation.
For instance, in option (B), here's what they do for op casts
lib/eigen_3.1.1/Eigen//src/plugins/CommonCwiseUnaryOps.h:
/** Overloaded for efficient real matrix times complex scalar value */
inline const CwiseUnaryOp<internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >, const Derived>
operator*(const std::complex<Scalar>& scalar) const
{
return CwiseUnaryOp<internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >, const Derived>
(*static_cast<const Derived*>(this), internal::scalar_multiple2_op<Scalar,std::complex<Scalar> >(scalar));
}
The problem for us [in addition to fueling Michael B's
faith in this wasteful paren style :-)] is that we need to go
one step further for efficiency. We need to override not
just the scalar ops, but the ops at matrix levels so we can
have efficient derivatives.
- Bob