Proposal for ColVector, etc.

14 views
Skip to first unread message

Ben Goodrich

unread,
Jan 17, 2012, 2:34:25 PM1/17/12
to stan development mailing list
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.

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>. 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. But I think the following is
possible with little cost:

-- Make the ColVector class inherit from the Matrix class
-- 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

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.

Ben

Bob Carpenter

unread,
Jan 17, 2012, 3:02:09 PM1/17/12
to stan...@googlegroups.com
It's a bit more complicated because Eigen's leaning on
C++ "concepts", not inheritance. I'll comment inline.

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

Ben Goodrich

unread,
Jan 17, 2012, 3:14:03 PM1/17/12
to stan development mailing list
OK. I think I mostly understand. If you can set up this part wherever
it needs to go:

> 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;
>
> };

I can make a branch that converts everything over to these idioms:

> 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;

That would be a little better.

Ben

Bob Carpenter

unread,
Jan 17, 2012, 3:23:26 PM1/17/12
to stan...@googlegroups.com
OK, I added this to file stan/maths/matrix.hpp.

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

Bob Carpenter

unread,
Jan 17, 2012, 3:31:04 PM1/17/12
to stan...@googlegroups.com
I just noticed I'd done it slightly differently
last time. So now there are two defs, and we
should only have one.

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:

Ben Goodrich

unread,
Jan 17, 2012, 4:24:05 PM1/17/12
to stan development mailing list
I think EigenType is good, in part because it emphasizes the
distinction between it and std::vector .
Reply all
Reply to author
Forward
0 new messages