For decades, Jack has wanted a language that would let him do arithmetic with vectors and matrices. Now he has it. Here's a summation of his work on vector and matrix classes.
By Jack W. Crenshaw
Transpose multiplies
On the other hand, operations like ATB are extremely common in matrix math. It seems a shame to create a new temporary every time you need to perform the operation. Furthermore, it's not really necessary to transpose either matrix, as long as you know what you're doing. After all, the matrix elements are stored in some order, and you know what that order is. So instead of moving the elements around, we only need to access them in a different order.
The authors of the old IBM Scientific Subroutine Package thought so, too. They supplied a subroutine (I think it was TMATX) to do the job. I've included that function in SimpleMat.cpp, under the name mTmult( ).
For about 40 years I managed to get by without feeling the need for the corresponding operation, ABT. Since memory is cheap these days, I went ahead and wrote mMultT( ) as well, (thereby violating Plauger's rule).
Be warned: the ground rules for these functions are tricky, tricky, tricky. When you multiply two matrices, the inner dimensions have to match. That is, the number of columns in the first matrix (say A) must match the number of rows in the second (B). The result has the rows of A, and the columns of B. In short:
(2)
The calling list for function mMult( ) has the form:
mMult(A, B, C, L, m, n);
Since we know that B must have m rows, we saw/see no reason to repeat it. The dimensions of the product, C will be L × n.
That's all well and good for the simple matrix product. But what if I'm going to be transposing A before the multiply? The call to mTmult( ) looks the same:
mTmult(A, B, C, L, m, n);
where, again, L and m represent the number of rows and columns in A. But this time, A is going to get conceptually tranposed to an (m × L) matrix before the multiply. So the inner dimension that B must match--that is, the row dimension of B--must be L, not m <!>. And it's a dimension not even mentioned in the calling list. The number of rows in the transposed A is m, not L, and so the dimensions of C must come out to be (m × n).
It gets even worse for the other case. In:
mMultT(A, B, C, L, m, n);
It's the B matrix that's transposed. The dimensions L and m still refer to the dimensions of A, and the number of rows in BT must still be equal to m. But that's the column dimension of B, not the row dimension. Therefore n must now be the row dimension.
If you find all this too confusing for words, not to worry. In many cases we're dealing with square matrices anyhow, so the dimensions are all equal. If they're not, you can always choose the simpler approach: first transpose one of the matrices, then multiply them.
When we get to the matrix class, it will be simpler yet. First of all, there is no T* or *T operator in C++, so there is nothing we can overload. The only operators I can think of that can appear on either side of an argument are ++ and --, but using them would be just too bizarre for words. So if you want to use the overloaded operators in class Matrix, you're going to have to settle for:
C=T(A)*B;
or:
C=A*T(B);
For the purist, I'm including functions in the matrix class called Tmult( ) and multT( ). They work the same as the functions in SimpleMat, except that you don't have to deal with the dimensions. Those dimensions are carried along as part of the objects, and the functions will check them and declare an error if they don't match up.