On 1/17/12 2:34 PM, Ben Goodrich wrote:
> In stan, there are a lot of functions whose arguments are something
> like
>
> const Matrix<T_loc,Dynamic,1>& mu
>
> This is less readable, hard to type, more prone to bugs, etc. than I
> think it could be, especially considering that we don't use any of the
> fixed size functionality in Eigen.
The place we used fixed sizes is for vectors and row-vectors,
as in the 1 above. Eigen specializes the Matrix template
for when one of the arguments is a fixed-size 1.
BUT, there are three more template arguments with defaults,
_Options, _MaxRows, and _MaxCols.
> For example, I have discovered (repeatedly) that if you write a test
> with something like
>
> Eigen::VectorXd mu(5)
> mu.setZero();
>
> and pass that, you get a compiler error even though VectorXd is a
> typedef for Matrix<double,Dynamic,1>.
Not quite. It's
typedef VectorX< double > VectorXd;
with
VectorX<T>
being its own template specialization of VectorBase. See:
http://eigen.tuxfamily.org/1/namespaceEigen.html#32b84ab7510b90d7b1e1fcd510163265
and
http://eigen.tuxfamily.org/1/classEigen_1_1VectorX.html
It may look like VectorX extends Matrix, but it's an
illusion. It just acts like a matrix in template
expressions (it's what they call a "concept" in C++
and the whole idea's so foreign from a Java perspective
that it keeps tripping me up).
One of the confusing things is that Matrix itself has
a templated constructor that'll accept anything that
acts enough like a matrix to provide values.
So it's not quite so easy to do what you want to do
directly.
We might be able to replace all the vector usages with
explicit VectorX operations. But it may be easier.
> Similarly,
>
> Eigen::MatrixXd mu(5,1);
> mu.setZero();
>
> and pass that, you get a compiler error because MatrixXd is a typedef
> for Matrix<double,Dynamic,Dynamic>.
>
> What I would like to write in function definitions is just
>
> const ColVector<T_loc>& mu
>
> I don't think it is possible to make ColVector a typedef and still
> pass a template parameter like T_loc.
Here's where using traits classes could help.
template <typename T>
struct EigenType {
typedef T scalar;
typedef Matrix<T,Dynamic,Dynamic> matrix;
typedef Matrix<T,Dynamic,1> vector;
typedef Matrix<T,1,Dynamic> row_vector;
};
Now you can use things like EigenType<T>::matrix
for a matrix of type T.
typename EigenType<T>::scalar
typename EigenType<T>::matrix
typename EigenType<T>::vector
typename EigenType<T>::row_vector
for types. In your example, that'd be:
const EigenType<T_loc>::vector& mu;
It might even require a typename first.
It's not great, but it's arguably clearer
and more abstracted than:
const Matrix<T_loc,Dynamic,1>& mu;
The nice part about this is that we know it'd work without
any compiler gymnastics.
There are already typedefs (matrix_d, matrix_v, etc.)
when the type is known in the code.
> But I think the following is
> possible with little cost:
>
> -- Make the ColVector class inherit from the Matrix class
This should probably be one of the Vector classes.
> -- Make "default" template parameters of Dynamic and 1 for
> RowsAtCompileTime and ColsAtCompileTime respectively
> -- Have the constructor throw an error if RowsAtCompileTime and
> ColsAtCompileTime are anything other than Dynamic and 1 respectively
This would presumably be a compile-time error.
> And the opposite for RowVector although I don't think we would use
> that much. Maybe also StanMatrix<type> where both RowsAtCompileTime
> and ColsAtCompileTime "default" to Dynamic and the constructor throws
> an error on anything but Dynamic?
>
> Thoughts? I'm not totally sure under the c++11 standard whether an
> inherited class can add default template parameters when the parent
> class leaves those template parameters undefaulted, but hopefully it
> does.
Apparently, you can. My design book recommends against changing
defaults in subclasses, though.
- Bob
So that's in namespace stan::maths.
You'll need to prefix the use of EigenType<T>::matrix
with "typename" if you use it as a template argument
itself. It's OK as is with variable declarations.
- Bob
I like the new version:
template<typename T>
>> struct EigenType {
>> typedef T scalar;
>> typedef Matrix<T,Dynamic,Dynamic> matrix;
>> typedef Matrix<T,Dynamic,1> vector;
>> typedef Matrix<T,1,Dynamic> row_vector;
>>
>> };
more than the old version:
template <typename T>
struct matrix_of {
/**
* Type of matrix with values of type <code>T</code>.
*/
typedef Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> type;
};
In practice, it's the difference between:
matrix_of<T_loc>::type
EigenType<T_loc>::matrix
Use whichever you prefer and I'll get rid of the other variety.
- Bob
On 1/17/12 3:14 PM, Ben Goodrich wrote: