Re: [eigen] inconsistent cwise() support |

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

On Tue, 17 Nov 2009, Gael Guennebaud wrote:

`I'm thinking that once we'll have a true array support, all this
``array/cwise stuff is going to be messy. Here I'll assume that a true
``Array class supporting the standard global math function (e.g.,
``std::sin) is really needed.
`

`I agree that we need an easy way to apply functions like sin
``coefficient-wise. However, the Array class has the disadvantage that A*B
``has different meaning depending on whether A and B are Matrix or Array.
`

`To me, that seems a serious issue, but perhaps I'm alone in that opinion.
``Nevertheless, let me discuss how to mitigate this. When the Array class is
``proposed, I thought that it was to support the different languages used in
``different domains (e.g., and rather crudely, theoretical linear algebra
``for Matrix, data manipulation for Array). A program in the first domain
``would use exclusively Matrix, and a program in the second domain would use
``exclusively Array. In that case, confusion is minimal, so I think that
``would be good programming style.
`

`However, now it's envisaged that Matrix and Array are freely mixed, and if
``cwise() is abolished it's even necessary to do so. So, the next best thing
``is to make sure that all your variables are Matrix (supposing you're in
``the theoretical linear algebra domain). As Gael said, this will lead to
``code like the following for componentwise multiplication = Hadamard
``product:
`
MatrixXd A = ...
MatrixXd B = ...
MatrixXd prod = (A.array() * B.array()).matrix();

`Not only is that cumbersome, but I think that it's more difficult to
``understand than A.cwise() * B.
`

`I think it is also important to acknowledge that the current cwise() API
``is odd enough to make it hard to learn for new comers. They often have
``some difficulties to determine where .cwise() is needed (e.g.,
``m1.cwise() * m2.cwise()), and how it propagates (though it does not, of
``course). For instance, if you look at "m1.cwise() * m2" and you know, or
``did not understand the prefix concept of .cwise(), then it seems that
``.cwise propagate to m2.
`

`I agree with this, cwise() is difficult, because of what you call the
``prefix concept: in A.cwise().max(B), cwise() modifies max, while C++
``programmers will think it modifies A. Perhaps a resolution would be to
``add a cwisemax() function to MatrixBase, so that we would replace
``A.cwise().max(B) to A.cwisemax(B). Now it's clear that the cwise prefix
``modifies max.
`

`With componentwise multiplication, that would mean that we replace
``A.cwise() * B by A.cwisemul(B). It's a pity that we lose the
``multiplication sign, but I think that we win on clarity: it's hard to
``misinterpret what A.cwisemul(B) would mean.
`

`With the addition of Array, that leads to the following API. The idea is
``that a module would use either the left or the right column, but not mix
``expressions.
`
Matrix A,B Array A,B
matrix multiply: A * B A.matrixmul(B)
c-wise multiply: A.cwisemul(B) A * B
matrix exponential: A.exp() A.matrixexp()
c-wise exponential: A.cwiseexp() A.exp()

`The discussion on whether to introduce global functions instead of (or in
``parallel of) member functions seems to be orthogonal to this, but just for
``illustration, this is how it would work with global functions.
`
Matrix A,B Array A,B
matrix multiply: A * B matrixmul(A,B)
c-wise multiply: cwisemul(A,B) A * B
matrix exponential: exp(A) matrixexp(A)
c-wise exponential: cwiseexp(A) exp(A)
Cheers,
Jitse