Cij = SUM{ Aik * Bkj }
for(Matrix_col_stream cj(C), bj(B); !cj.total_eof(); cj.next_column(), bj.next_column()) for(Matrix_row_stream ai(A); !ai.total_eof(); ai.next_row(), bj.rewind()) { register double cij = 0; while( !ai.eof() ) cij += ai.get() * bj.get(); cj.put(cij); }
void Matrix::_AmultB(const Matrix& A, const Matrix& B) { A.is_valid(); B.is_valid(); if( A.ncols != B.nrows || A.col_lwb != B.row_lwb ) A.info(), B.info(), _error("matrices above cannot be multiplied"); allocate(A.nrows,B.ncols,A.row_lwb,B.col_lwb); register REAL * arp; // Pointer to the i-th row of A REAL * bcp = B.elements; // Pointer to the j-th col of B register REAL * cp = elements; // C is to be traversed in the natural while( cp < elements + nelems ) // order, col-after-col { for(arp = A.elements; arp < A.elements + A.nrows; ) { register double cij = 0; register REAL * bccp = bcp; // To scan the jth col of B while( arp < A.elements + A.nelems ) // Scan the i-th row of A and cij += *bccp++ * *arp, arp += A.nrows; // the j-th col of B *cp++ = cij; arp -= A.nelems - 1; // arp points to (i+1)-th row } bcp += B.nrows; // We're done with j-th col of both } // B and C. Set bcp to the (j+1)-th col assert( cp == elements + nelems && bcp == B.elements + B.nelems ); }
The snippet with Matrix_stream is pseudocode. Although with Matrix_row_stream/Matrix_col_stream implementations (which is a piece of cake) it becomes a full-blown working code.
Note, there is no direct access to any element of the matrix anywhere
in the code; everything is done in terms of the 'current' (element,
row, col) and the next (element, row, col). If you're saying it's all
so corny, here's a less trivial example
Mathematical algorithm seems to require a direct access to matrices. But it's not necessary. The whole deal is just traversing matrices in some specific ways.