Matrices, do you hate them? I do, and they turn up all over the place in the projects I work with. So over time
I have developed a class
CMatrix to handle all the things we need, and some I expect to need in the future.
How the data is handled
First lets take an overview of how the class handles the data. The matrix data is allocated in
a flat array of
doubles with an integer reference counter at the end of the array. As the matrix is dynamic, we
use a reference count system to avoid efficiency hits when assigning/copying one matrix into another. Two object can point to
the same data, and they only diverge when one of them changes the data, getting its own copy of the data at that point.
The data is only deleted when the last reference to it is being deleted. This has advantages for objects returned by function
calls by value, and which are assigned by
operator=, as there is little penalty in assigning a pointer compared to
CMatrix class inherits directly from
CObject and is full serialization compatible.
A small helper class has been added to allow a simulated
CMatrix::operator to work. I stole
this idea shamelessly from Alex Chirokov's article 2D Matrix
Container with  indexing. A nice way of doing it. Note also that you should not be creating any objects of this type in your
own code. It is used for this purpose only.
In DEBUG mode, the code compiles with 0 warnings/errors and has extensive ASSERTion checking through out, so it should catch any
problems that you have (or I have) in code. Most of the functionality has been
thoroughly checked, but I would recommend checking your
results, just in case!
You can construct a matrix object using the following methods:
CMatrix() Constructs a 1 * 1 array, this is the default constructor.
CMatrix(CMatrix& other) Copy constructor
CMatrix(nCols, nRows) Constructs a matrix of
nCols * nRows dimensions. All data is 0.
CMatrix(size, diagonal) Constructs a square matrix with or without 1's on the diagonal.
CMatrix(VARIANT) Constructs a
CMatrix object from a 2 dimension
As a note, any non-initialized matrix elements will be set to 0 on construction.
The following operators have been overloaded:
operator=(CMatrix) For standard assignment.
operator+(CMatrix) Adds 2 matrices together, must be the same size
operator-(CMatrix) Subtracts 1 matrix from another, must be the same size
operator*(CMatrix) Multiples 2 matrices together, the two inner
dimensions must be the same, e.g. 3*2 by 2*3
operator+=(CMatrix) Adds one matrix onto the current matrix, must have same dimensions.
operator-=(CMatrix) Subtracts one matrix from the current matrix, must have same dimensions.
operator*=(CMatrix) Mutiples the current matrix by the other matrix
operator*=(double) Multiples all matrix elements by the given value
operator*(CMatrix, double) Multiples all elements by the given value, returning a new matrix
operator==(CMatrix) For matrix comparison, returns
true if identical,
operator(int) Works with the class
CMatrixHelper to simulate a
Two standard access function are provided.:
GetElement(nCol, nRow) returns the given element value
SetElement(nCol, nRow, value) Sets the given element to a different value
Other matrix functions
GetNumColumns() Returns the matrices columns dimension
GetNumRows() Returns the matrices rows dimension
SumColumn(column) Returns the sum of all elements in the given column
SumRow(row) Returns the sum of all elements in the given row
SumColumnSquared(column) Same as
SumColumn() but the return value is squared
SumRowSquared(row) Same as
SumRow() but the return value is squared
GetNumericRange(min, max) Returns the lower and upper values of elements in the matrix
GetSafeArray() Returns a
VARIANT with a copy of the
CMatrix data in a
SAFEARRAY. Note that the
be cleared using
VariantClear(var) unless you pass the
VARIANT to a different program (e.g. a COM component/VB) as it
becomes their responsibility.
CopyToClipboard() Places the
CMatrix data in the clipboard as CSV text, use this when debugging etc
WriteAsCSVFile(filename) Writes the matrix to a CSV file
ReadFromCSVFile(const CString& filename) Creates a new matrix from a CSV file.
Dump() TRACEs the matrix content to the debug stream
AssertValid() ASSERTs if the object is in an invalid state
GetTransposed() Returns a new matrix which is a Transpose of the one called on
Transpose() Transposes the current matrix
GetInverted() Returns the inversion of the current matrix
Invert() Inverts the current matrix
Covariant (A' * A)
Covariant() Returns the Covariant of the current matrix
GetNormalised(min, max) Returns the matrix with all values scaled between min and max
Normalise(min, max) Normalizes all values in the matrix between min and max
GetConcatinatedColumns(CMatrix) Returns a new matrix with the other matrix added onto the right hand side
ConcatinateColumns(CMatrix) Concatenates the additional columns onto the current matrix
GetConcatenatedRows(CMatrix) Returns a new matrix with the other matrix added onto the bottom of the current matrix
ConcatinateRows(CMatrix) Concatenates the additional rows onto the current matrix
AddColumn(double*) Adds a new column onto the current matrix
AddRow(double*) Adds a new row onto the current matrix
ExtractSubMatrix(x, y, x_size, y_size) Extract a sub matrix from a larger matrix
SetSubMatrix(x, y, CMatrix) Substitutes a larger matrices elements with those from another matrix
ExtractDiagonal() Returns a x * 1 matrix with the values from the diagonal - square matrices only
GetSquareMatrix() Returns a square matrix of the smaller dimension, by stepping over rows/columns to make the matrix square
MakeSquare() Squares the current matrix by stepping over rows/columns
All the code to handle the allocation/deallocation of matrix data and the reference counting is not covered here in the class interface
as they are all
private functions. You can see the documentation in the source code comments. (wow comments.... )
If you find any bugs or have some enhancements for the class, I would be happy if you would pass them along, and I will endeavour to keep
the class fully up to date here.
13th August 2002
- A small problem with
CMatrixHelper when using
operator for element read access was fixed by making the return object
- An invalid ASSERTion error in
ExtractSubMatrix was fixed.
CMatrixHelper now copies all member variables across into the target object.
2nd July 2002
- A small typo in
CMatrix::Invert() was fixed. Thanks to Jamie Plowman for spotting it.
- As suggested, I made the class
protected and made
so that only
CMatrix can construct objects, not a user.