views:

111

answers:

3

Aye it's been done a million times before, but damnit I want to do it again. I'm writing a simple Matrix Library for C++ with the intention of doing it right. I've come across something that's fairly obvious in mathematics, but not so obvious to a strongly typed system -- the fact that a 1x1 matrix is just a number. To avoid this, I started walking down the hairy path of matrices as a composition of vectors, but also stumbled upon the fact that two vectors multiplied together could either be a number or a dyad, depending on the orientation of the two.

My question is, what is the right way to deal with this situation in a strongly typed language like C++ or Java?

+2  A: 

If you aren't worried about SIMD optimisations and the like then I would have thought the best way would be to set up a templated tensor. Choose your maximum tensor dimensions and then you can do things like this:

typedef Tensor3D< float, 4, 1, 1 > Vector4;

And so forth. The mathematics, if implemented correctly, will just work with all forms of "matrix" and "vector". Both are, afterall, just special cases of tensors.

Edit: knowing the size of a template is actually pretty easy. Add in a GetRows() etc function and you can return the value you pass into the template at instantiation.

ie

template< typename T, int rows, int cols > class Tensor2D
{
public:
    int GetRows() { return rows; }
    int GetCols() { return cols; }
};
Goz
Speaking of Templates, I was trying to figure out how to properly implement one in a split .h/.cpp file, but was filled with link errors. http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12 shed some light, but I'm still a tad unclear; is it just not possible? They must be declared and implemented in the same place?
duckworthd
@duck For all practical purposes, it's not possible.
FredOverflow
@duckworthd: you can implement the code in a separate file but you would need to `#include` that separate file at the end of your `.h` file.However this is not really like having a separate `.h` and `.cpp` file for e.g. a class.
MKroehnert
@Goz: could you direct me to where I could learn to use templates with restricted types? For example, If I have a 4x5 matrix and a 5x1 vector, I want to make a result that's 4x1, but how can I get that information from a template?
duckworthd
+3  A: 

something that's fairly obvious in mathematics, but not so obvious to a strongly typed system -- the fact that a 1x1 matrix is just a number.

That's arguable. A hardcore mathematician (I'm not) would probably argue against it, he would say that a 1x1 matrix can be regarded as isomorphic (or something like that) to a scalar, but they are conceptually different things. Only in some informal sense "a 1x1 matrix is a scalar" (similar, though stronger, that a complex number without an imaginary part "is a real").

I don't think that that correspondence should be reflected in a strong typed language. And I dont' think it is, in typical implementations (of complex or matrix), eg. Java Apache Commons Math. For example, a Complex with zero imaginary part is not a Number (from the type POV - they cannot be casted one into another).

In the case of matrices, the correspondence is even more disputable. Should we be able to multiply two matrices of sizes (4x3) x (1x1) ? If we regard the second as a scalar, it's valid, but not as a matrix, since it violates the restriction on matrix dimensions for multiplication. And I believe Commons sticks to that.

In a weakly typed language (eg Matlab) it would be another story.

leonbloy
"Should we be able to multiply two matrices of sizes (4x3) x (1x1)?" - you can if that second item is scalar, but not if it's a matrix. That fails to obey the rules for matrix multiplication.
duffymo
@duffymo: that's my point
leonbloy
+1: I'm with @leonbloy on this. I also suggest that you make sure to allow for 0x0 matrices which will prevent some corner cases in matrix algorithms (eg the lower triangle of a 1x1 matrix) becoming problems.
High Performance Mark
If someone wanted to multiply a 4x3 matrix by a 1x1 matrix, it's likely they've made a mistake. It would be analogous to adding 3 kilograms and 4 meters: you can add the numbers, but you probably don't want to.
John D. Cook
A: 

My advice? Don't worry about the 1x1 case and sleep at night. You shouldn't be worried about any uses suddenly deciding to use your library to model a bunch of numbers as 1x1 matricies and complaining about your implementation.

No one who solves these problems will be so foolish. If you're smart enough to use matricies, you're smart enough to use them properly.

As for all the permutations that scalars introduce, I'd say that you must account for them. As a matrix library user, I'd expect to be able to multiply two matricies together to get another matrix, a matrix by a (column or row) vector get a vector result, and a scalar times a matrix to get another matrix.

If I multiply two vectors I can get a scalar (inner product) or a matrix (outer product). Your library had better give them to me.

It's not trivial. It's been done "right" by others, but kudos to working it through for yourself.

duffymo