Boost logo

Boost :

From: Jason Kraftcheck (kraftche_at_[hidden])
Date: 2006-11-09 11:35:16


Jason Hise wrote:
> On 11/8/06, Jason Kraftcheck <kraftche_at_[hidden]> wrote:
>> Jason Hise wrote:
>>> I did something very much like this a while back, which was submitted
>>> as a potential jumping off point for a boost geometry library. It is
>>> in the boost vault under Math - Geometry (http://tinyurl.com/ymjsoz),
>>> along with two other submissions. (Mine is geometryJH_01.zip).
>>>
>> I think that my design of the matrix class is a little better because a vector
>> is defined as a Nx1 matrix, rather than the matrix being defined as an array of
>> vectors. This avoids the need for special operators for vector-matrix
>> multiplication, is closer to the underlying mathematical concept, and makes the
>> equivalency of a vector and column matrix explicit.
>
> I suppose this makes sense from an efficiency standpoint. I prefered
> the matrix as a vector of vectors because it made defining algorithms
> in terms of elementary row operations cleaner, and because it allowed
> the more natural syntax of indexing the matrix as though it were a 2D
> array.

Indexing the matrix as if it were a 2D array can be accomplished other ways.
For example:
  private:
    Type data[R*C];
  public:
    Type operator[](unsigned i) { return data+i*C; }
    const Type* operator[](unsigned i) const { return data+i*C; }

To index it as if it were a 2D array, the operator[] must return something that
also has an operator[]. An array of works as well as a vector.

And I fail to see how row operations make the implementation cleaner or easier.
 Most operators can be implemented with a single loop in both cases. For example:
  private:
    Type data[R*C];
  public:
    matrix<R,C,Type>& operator+=( const matrix<R,C,Type>& other ) {
      for (unsigned i = 0; i < R*C; ++i)
        data[i] += other.data[i];
      return *this;
    }

>
> There are two usability features that my implementation provides which
> yours does not. The first is being able to index a vector by name
> (_x, _y, _z, _w). This is easily implemented using a properly scoped
> enum. I used leading underscores for my component names as a
> convention to indicate that they were property names, though
> admittedly this naming convention could be debated.
>
> vector <float, 3> up;
> up[_x] = 0;
> up[_y] = 1;
> up[_z] = 0;
>

I've never found such a convention very useful. It is a trivial thing to add if
others do.

> Another thing that my code allows that yours does not is explicit
> construction of a vector from the number of parameters that matches
> the size (at least from 1 through 4), using the SFINAE techniques of
> boost.enable_if. It can be much nicer for client code to be able to
> write:
>
> vector <float, 3> up (0, 1, 0);
>
> than to have to write the code segment I used for my previous example.

That is a useful feature. I had considered several ways of implementing it.
However, I had doubts about all of them, so I didn't provide any.

1) varargs
    o matrix( Type ii, ... );
    o no type checking on arguments
2) multiple constructors with different numbers of args
    o what you have implemented
    o seems conceptually wrong to have a four-arg constructor
       for a 2-element vector, or visa versa.
    o doesn't work for larger matrices
3) one constructor with unrolled assignment
    o most of the same limitations as 2)
    o one function
    o safe (will never write off the end of the array)
    o matrix( Type a, Type b , Type c = 0, Type d = 0,
              Type e = 0, Type f = 0, Type g = 0, Type h = 0,
              Type i = 0, Type j = 0, Type k = 0, Type l = 0,
              Type m = 0, Type n = 0, Type o = 0, Type p = 0 ) {
        switch (R*C) {
           case 16: data[15] = p;
           case 15: data[14] = o;
           ...
           case 1: data[ 0] = a;
       }
    o excessively large argument list for e.g. a 2x1 matrix

- jason


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk