A few last notes. Multiplication operations are pretty robust, as is addition and subtraction. I was able to get lu().solve() to work with mixed types as well, but it required a change to Eigen code. It's necessitated by the overloading of is_same<double,var>. I'm going to see if I can remove the overloads of is_same and still get things to compile.
Strategically, it seems to me that if that was
all that was necessary, they would've done it themselves
for complex values. (That is, you can assign a double
to a complex, but not vice-versa.)
That's not really changing the Eigen code so much
as adding a template specialization. We've already done
that for specifying the behavior of var as a scalar.
I'm pretty sure, though don't seem to have convinced
anyone else, that auto-dif is going to be at least
as hard to add as complex.
- Bob
The problem is that I don't think we have extensive
enough unit tests for matrix auto-dif. The reason
was that we were just pushing var through templated
ops. Before I'd trust a change this major, I'm going
to want to put all the relevant unit tests in.
The only way that using the Eigen expression templates
is going to be a win is if we can push the auto-dif
partial evals through them. The cost of doing auto-dif
badly is way higher than the cost of not using expression
templates (we actually DO use all their experssion templates
internally once things get converted to var).
I'm really wishing we'd done a univariate version of
Stan first. It would've been done ages ago and I'd
be less uptight about making major changes on the "eve"
of our first release.
- Bob
Before committing changes that are that major,
we should probably talk about them.
The problem is that I don't think we have extensive
enough unit tests for matrix auto-dif. The reason
was that we were just pushing var through templated
ops. Before I'd trust a change this major, I'm going
to want to put all the relevant unit tests in.
The only way that using the Eigen expression templates
is going to be a win is if we can push the auto-dif
partial evals through them. The cost of doing auto-dif
badly is way higher than the cost of not using expression
templates (we actually DO use all their experssion templates
internally once things get converted to var).
On 4/13/12 12:30 PM, Marcus Brubaker wrote:
> Just to be clear, these changes are in the mixed_type branch, not the master branch.
Perfect. I missed that the first time around,
though you were very clear about it.
I've been planning to dive back into Eigen and do
this right when we got a chance, so it's great you're
exploring it. In fact, tighter integration of auto-dif
with Eigen is a deliverable on our NSF proposal.
The Eigen developers would like us to do that, too.
It's not a priority for them, but they'd like to
have a decent auto-dif implementation and what's stopping
them is the mixed types. What keeps bugging me
about the simpler solutions is that it seems that if there
was a simple solution, they'd have just used that.
You might also ping the Eigen list -- they're very good
about responding to this kind of request about how
their system's put together and how to work with it.
> I don't see this as something to
> target for the first release. Rather it's just a side line of development for a hopefully cleaner and more efficient
> implementation of matrix operations.
Agreed. What I have in place now is very
brute force and not at all the right way to do
the integration with Eigen.
> What we have right now in the master branch is fully functional and reasonably efficient, particularly with the latest
> dot_product related changes.
Thanks again!
I still need to get in and write a sufficient
set of unit tests. Then I'll be much more confident
when it comes time to merge the branch.
- Bob
> The problem is that I don't think we have extensive
> enough unit tests for matrix auto-dif. The reason
> was that we were just pushing var through templated
> ops. Before I'd trust a change this major, I'm going
> to want to put all the relevant unit tests in.
>
> Presumably, we would be adding unit tests to the mixed_type branch, so that if and when it is ever ready to merge into
> the master branch, the tests would get merged too.
I think the tests can all go in the master branch.
But if it's easier to put them in the branch and then
merge back, it's not a big deal.
> The only way that using the Eigen expression templates
> is going to be a win is if we can push the auto-dif
> partial evals through them. The cost of doing auto-dif
> badly is way higher than the cost of not using expression
> templates (we actually DO use all their experssion templates
> internally once things get converted to var).
>
> As a first cut, we can use the .eval() postfix to evaluate an expression immediately. If I am understanding correctly,
> adding all the .eval() postfixes would essentially yield the same performance that we have now but would allow us to
> eliminate or simplify code.
Right -- eval() just creates a new proper matrix and
assigns the value of the expression template to it.
> We could then gradually remove the .eval() postfixes and replace them with our own templated
> versions where there are performance bottlenecks.
Exactly.
- Bob
I've been planning to dive back into Eigen and do
this right when we got a chance, so it's great you're
exploring it. In fact, tighter integration of auto-dif
with Eigen is a deliverable on our NSF proposal.
The Eigen developers would like us to do that, too.
It's not a priority for them, but they'd like to
have a decent auto-dif implementation and what's stopping
them is the mixed types. What keeps bugging me
about the simpler solutions is that it seems that if there
was a simple solution, they'd have just used that.
You might also ping the Eigen list -- they're very good
about responding to this kind of request about how
their system's put together and how to work with it.
The folks at Eigen are already thinking about this.
Apparently, it already works for products, but not
for sums, etc.
We even put in a feature request that's now on their
bug tracker.
Some refs:
Eigen to-do list:
http://eigen.tuxfamily.org/index.php?title=Todo
Support for complex numbers and mixing complex-real is already pretty good. However, some operations are not vectorized
or fully optimized yet. E.g., complex-real scalar (or coeff wise) products. Complex normalization, etc.
Eigen issue tracker:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=279
(From Gael Guennebaud)
We should also extend the mixing of types to other operations than products. It
makes perfect sens to add complex to real, or substract scalars and autodiff
variables.
All this information could be provide through a unique:
template<A,B> struct PromoteType { typedef XXX ResulType; };
By default, when A!=B, this class would be empty and we could detect that to
trigger a static assertion.
So this is more like a generalization of our current scalar_product_traits and
generalization of our current static assertions in BinaryOp.
... snip ...
(From Gael Gunnebaud):
That said, we already have a template struct to control the returned scalar
type of mixed products, e.g.:
namespace Eigen{
namespace internal{
template<typename T> struct scalar_product_traits<std::complex<T>, T>
{
typedef std::complex<T> ReturnType;
};
}
}
- Bob
Thanks for the git tips. I'm really loving it
and I've barely scratched the surface of its functionality.I think the tests can all go in the master branch.
The problem is that I don't think we have extensive
enough unit tests for matrix auto-dif. The reason
was that we were just pushing var through templated
ops. Before I'd trust a change this major, I'm going
to want to put all the relevant unit tests in.
Presumably, we would be adding unit tests to the mixed_type branch, so that if and when it is ever ready to merge into
the master branch, the tests would get merged too.
But if it's easier to put them in the branch and then
merge back, it's not a big deal.
Right -- eval() just creates a new proper matrix and
The only way that using the Eigen expression templates
is going to be a win is if we can push the auto-dif
partial evals through them. The cost of doing auto-dif
badly is way higher than the cost of not using expression
templates (we actually DO use all their experssion templates
internally once things get converted to var).
As a first cut, we can use the .eval() postfix to evaluate an expression immediately. If I am understanding correctly,
adding all the .eval() postfixes would essentially yield the same performance that we have now but would allow us to
eliminate or simplify code.
assigns the value of the expression template to it.
On 4/13/12 1:04 PM, Marcus Brubaker wrote:
I should've been clearer -- it's just in the solvers once
we've converted to var.
> Any time we write multiply() or add() or
> dot_product() in the code, the expression gets evaluated to an Eigen::Matrix, i.e., .eval() is already implicitly called
> all over the place.
Techncially, eval() isn't actually called, just
operator(), but it has exactly the same effect -- copying
the entries implicitly defined in an Eigen expression template
into an explicit matrix.
> Since those functions are the only sensible way to write templated functions like multi_normal_log,
> they are the primary ones that get used.
>
> At any rate, shifting over to make use of them should largely be a matter of changing the types passed around by
> functions to Eigen::EigenBase instead of Eigen::Matrix.
Right -- it should really simplify things from
the code side and let us get rid of most of
stan/math/matrix.hpp
- Bob