MatrixViews

© 2008 John Abbott
GNU Free Documentation License, Version 1.2



index page

User documentation for MatrixViews

Matrix views in CoCoALib allow one to view one or more objects as though they were a matrix. It is important to remember that a MatrixView merely offers a means to view existing objects: if you destroy or change the structure of those objects then the view may become invalid (and using it could lead to the dreaded undefined behaviour, i.e. probably a crash).

Here are the pseudo-constructors:

    ZeroMat(R, r, c)  -- create an r-by-c zero matrix over R
                            (note: no entry is //writable//)
  
    IdentityMat(R, n) -- create an n-by-n identity matrix over R
                            (note: no entry is //writable//)
  
    transpose(M)         -- create a transposed //view// of the matrix M
  
    submatrix(M, rows, cols) -- create a submatrix //view// into M; the
                            rows and columns visible in the submatrix
                            are those specified in the arguments rows
                            and cols (which are of type ``std::vector``)

You can view a std::vector<RingElem>, all of whose entries belong to the same ring, as a matrix in three ways:

    ColMat(v)        -- view a ``vector<RingElem>`` as a column matrix
  
    RowMat(v)        -- view a ``vector<RingElem>`` as a row matrix
  
    DiagMat(v)       -- view a ``vector<RingElem>`` as a diagonal matrix
                           (note: only the diagonal entries are //writable//)

The following pseudo-constructors assemble several matrices into a bigger one; the argument matrices must all have the same BaseRing.

    ConcatVer(A, B)     -- create a matrix //view// with the rows of A above those of B
  
    ConcatHor(A, B)     -- create a matrix //view// with the cols of A before those of B
  
    ConcatDiag(A,B)     -- create the block diagonal matrix //view//  (A 0)
                                                                      (0 B)
  
    ConcatAntiDiag(A,B) -- create the block antidiagonal matrix //view//  (0 A)
                                                                          (B 0)
  
    BlockMat(A, B, C, D) -- create the block matrix //view//   (A B)
                                                               (C D)
                            NB the boundaries of the four submatrices must be aligned.

Here are the operations on a MatrixView object

    MV(i,j)              -- the (i,j) entry in the matrix view MV.
  
    out << MV            -- prints MV as a //dense// matrix
  
    IsZeroRow(MV, i)     -- true iff the i-th row is zero
  
    IsZeroCol(MV, j)     -- true iff the j-th column is zero
  
    MV->myIsWritable(i,j)-- true iff the (i,j) entry can be written to.
  
    SetEntry(MV,i,j, val)-- set (i,j) entry to val
                            (throws ERR::ConstMatEntry if the entry is not writable)
  
    MV->myRefEntry(i,j)  -- reference to (i,j) entry
                            (may be called only if the (i,j) is writable)
  
    MV->myAssignZero()   -- sets all entries to zero
                            (throws ERR::ConstMatEntry if not all entries can be made zero)

Maintainer documentation for MatrixViews

Most of the implementations are quite straightforward; the tricky part was getting the design of the abstract classes right (well, I hope it is right now). Below are a few comments on some less obvious aspects of the implementations.

Note: it is a mathematical fact that the determinant of the 0x0 matrix is 1.

ZeroMatImpl and IdentityMatImpl are both derived from MatrixViewBase rather than ConstMatrixViewBase as one might naturally expect. The main reason for this is to simplify the implementation of BlockMat views. I wanted to be lazy and implement ConcatDiag and ConcatAntidiag using BlockMat; while this may not be the best implementation, it is a natural approach and should certainly work as one might reasonably expect. However, the pseudo-ctor BlockMat has just two signatures: if any one of the submatrices is const then whole result becomes const. I didn't want to implement sixteen different signatures for BlockMat, and the easy way out seemed to be to make ZeroMatImpl and IdentityMatImpl non-const. As a consequence there are a number of useless member functions in ZeroMatImpl and IdentityMatImpl. I believe this compromise is reasonable. It seemed reasonable to allow ZeroMatImpl::myAssignZero to succeed.

There is a small problem with creating a matrix from an empty std::vector because there is no indication of what the base ring should be. I have chosen to throw an error if one tries to create a matrix view from an empty vector (in RowMat, ColMat and DiagMat).

The routines which access the (i,j) entry in a BlockMat are messy. I could not see an elegant way to make them simpler (or to avoid repeating similar structure in several places in the code). See Bugs about implementing BlockMat in terms of ConcatVer and ConcatHor.

Bugs, Shortcomings and other ideas

There is an appalling amount of code duplication in the implementations. I do not yet see a good way of reducing this. I hope someone will sooner or later find an elegant way to avoid the duplication.

It is a great nuisance to have to implement two very similar classes: one for the const case, and the other for the non-const case. Is there a better way?

Add ColMat, RowMat and DiagMat for a free module element?

Should submatrix allow repeated row/col indices? It could lead to some some funny behaviour (e.g. setting one entry may change other entries), so perhaps it would be better to forbid it? Currently, it is forbidden.

The pseudo-ctor for submatrix ought to accept begin/end iterators instead of insisting that the caller put the indices in std::vectors.

Should there be a more general version of BlockMat which allows non-aligned borders? BlockMat could be eliminated and replaced by suitable calls to ConcatVer and ConcatHor.