A matrix class that illustrates the use of templates etc.

Post Reply
KBleivik
Site Admin
Posts: 88
Joined: Tue Jan 31, 2006 3:10 pm
Location: Moss Norway
Contact:

A matrix class that illustrates the use of templates etc.

Post by KBleivik »

/*

The Matrix class is inspired by Bjarne Stroustrup "The C++ programming Language
Second Edition" Addison-Wesley Publishing Company 1992 page 236, Bjarne Strostrup
"The Design and Evolution of C++" Addison-Wesley Publishing Company 1994
chapter 15 - 17 , Ira Pohl "Objectoriented programming in C++" Benjamin/Cummings
Publishing Company, Inc. 1993 page 256 -> , Andrew Koenig "Arrays and inheritance
don't mix" C++ Report March - April 1993 page 22 - 23, Andrew Koenig "Multi-
dimensional arrays and new-expressions" C++ Report February 1994 page 51 - 52 ,
Andrew Koenig "Hints for keeping bugs away" C++ Report November-December 1994
page 37 - 39, Andrew Koenig "Templates and generic algorithms" JOOP june 1994,
Andrew Koenig "Surrogate classes in C++" JOOP july - august 1994. John Barton
and Lee R. Nackman "Scientific & Engineering Programming in C++" C++ Report
September 1993 page 26 - 31, November - December 1993 page 42 - 47, May 1994
page 47 - 50 and 56, July - August 1994 page 59 - 63, October 1994 page 57 - 62,
Margaret Ellis and Martin Caroll "Inheritance-based vs. template based con-
tainers" C++ Report March - April 1993 page 17 - 20, Margaret Ellis and Martin
Caroll "Tradeoffs of interface classes" C++ Report January 1995 page 29 - 32.
Margaret Ellis and Martin Caroll "What functions should all classes provide?"
C++ Report November-December 1994 page 26 - 33, Tom Cargill "Exception handling:
A false sense of security" C++ Report November - December 1994 page 21 - 24,
David R. Reed "Using C++ exceptions" C++ Report March - April 1994 page 18 - 27,
Scott Meyers "Our Friend, the assignment operator" C++ Report May 1994 page 51 -
53 and 56 and Scott Meyers "Operator=: The readers fight back" C++ Report
November December 1994 page 17 - 20 and the C++ Puzzle C++ Report January 1995
page 71 - 72.

Portability issues: Rainer Gerhards: "Using header files to enhance portability"
The C Users Journal january 1990, Andy Nicholson "64-bit Programming in a 32-
bit World" Dr. Dobb's Journal january 1993 and Peter Becker "Writing portable C++
code" C++ Report September 1994.

*/

#include <iostream.h>
#include <stdlib.h>
#include <assert.h>

//enum boolean{false, true};

template <class T> class Matrix

/*
For efficiency! Do we need a service non-template base class? See C++ report Nov-Dec 1993 page 43. For a general note on efficiency see page 43 - 44. What is most important user friendliness, reliability or raw speed? See also C++ Report october 1994 page 57 - 62 on concrete class, function templates and interface base classes.
*/

{
private:
int rSize, cSize; //rSize = rowsize, cSize=columsize
T **pp; // Pointer to pointer of type T.
public:
int numRows() const
{
return rSize;
}

int numCols() const
{
return cSize;
}

Matrix() : rSize(3), cSize(3) //Default constructor 3 by 3 type T matrix.
{ //Importance of Default constructor. See
pp = new T*[3]; //C++ Report September 1993 page 28.
pp[0] = new T[3]; //No test for available memory implemented yet.
pp[1] = new T[3];
pp[2] = new T[3];
}

Matrix(int r, int c); //Parameterized constructor.

~Matrix(); // Destructor.

Matrix(const Matrix<T> &m); // Copy constructor

T& operator()(int i, int j) // No range check. See C++ Report september 1993
// page 30 for reason why.
{
return(pp[j]);
}

const T& operator()(int i, int j) const
{
return(pp[j]);
}

// Not implemented.
Matrix<T>& operator=(const Matrix<T> &rhs); //C++ Report May 1994 page 51,
//C++ Report Nov.-Dec. 1994 page 17
Matrix<T>& operator==(const Matrix<T> &rhs); //C++ Report Nov.-Dec. 1994 page 26

Matrix<T>& operator+=(const Matrix<T> &m);

Matrix<T>& operator-=(const Matrix<T> &m); // Not implemented.

Matrix<T>& operator*=(const Matrix<T> &m); // Not implemented.

// The reason why some operators are implemented as friends to the class
// is discussed in C++ Report September 1993 page 30.

friend Matrix<T> operator*(const Matrix<T> &m1, const Matrix<T> &m2);

friend Matrix<T> operator+(const Matrix<T> &m1, const Matrix<T> &m2);

friend Matrix<T> operator-(const Matrix<T> &m1, const Matrix<T> &m2);

friend istream &operator>>(istream &stream, const Matrix<T> &m);

friend ostream &operator<<(ostream &steram, const Matrix<T> &m);

friend Matrix<T>& inv(const Matrix<T> &m); //Matrix inversion.
//Not implemented.

Matrix<T>& scalarMatProd(const T t, const Matrix<T> &m); //Not implemented

friend Matrix<T> kronProd(const Matrix<T> &m1, const Matrix<T> &m2);

/*
And a lot of other important Matrix functions, eigen value routines,
Cholesky decomposition, Generalized inverses etc.
*/

};

template<class T>
inline // For compilers supporting loops in inline functions.
Matrix<T>::Matrix(int r, int c) : rSize(r), cSize(c)
{
if (r <= 0) { // Can also make an exception class. See C++ Report
// September 1993 page 30.
cerr << "Illegal row size: " << r << endl;
exit(1);
}
if (c <= 0) {
cerr << "Illegal column size: " << c << endl;
exit(1);
}
pp = new T*[c]; // c type T pointers. See Koenig C++ Report
for (int i = 0; i < r; ++i) // february 1994 page 52. No test for avail-
// able memory implemented yet.
pp = new T[r]; //Each pointer points at the initial element of an
// r-element type T array.
}
template<class T>
inline
Matrix<T>::~Matrix()
{
for (int i = 0; i < cSize; ++i)
delete [] pp;
delete [] pp;
}

template<class T>
inline
Matrix<T>::
Matrix(const Matrix<T> &m) : rSize(m.rSize), cSize(m.cSize)
{
int i, j;
pp = new T*[cSize];
for (i = 0; i < cSize; ++i)
pp = new T[rSize];
for (i = 0; i < cSize; ++i)
for (j = 0; j < rSize; ++j)
pp[j] = m.pp[j];
}


template<class T>
inline
Matrix<T>& Matrix<T>::
operator=(const Matrix<T>& m) // No test for self assignment implemented yet.
{
assert(m.cSize == cSize && m.rSize == rSize);
for (int i = 0; i < cSize; ++i)
for (int j = 0; j < rSize; ++j)
pp[j] = m.pp[j];
return (*this); // Returns the actual total object.
}

template<class T>
Matrix<T>& Matrix<T>::
operator+=(const Matrix<T>& m)
{
assert(m.cSize == cSize && m.rSize == rSize);
for (int i = 0; i < cSize; ++i)
for (int j = 0; j < rSize; ++j)
pp[j] += m.pp[i][j];
return (*this); // Returns the actual total object.
}

template<class T>
ostream
&operator<<(ostream &stream, const Matrix<T> &m) //Barton & Nackman C++
{ // Report September 1993 page 29
for (int i = 0; i < m.numRows(); i++) {
for (int j = 0; j < m.numCols(); j++) {
stream << m(i,j) << " ";
}
stream << endl;
}
return stream;
}

template<class T>
istream
&operator>>(istream &stream, const Matrix<T> &m)
{
for (int i = 0; i < m.numRows(); i++) {
for (int j = 0; j < m.numCols(); j++) {
cout << "Matrix[" << i << "][" << j << "] : ";
stream >> m.pp[i][j];
}
cout << endl;
}
return stream;
}


template<class T>
Matrix<T>
kronProd(const Matrix<T> &m1, const Matrix<T> &m2)
{
Matrix<T> m3(m1.rSize*m2.rSize, m1.cSize*m2.cSize);
int i, j, k, l, m, n, a, b, c, d;
a = m1.numRows();
b = m1.numCols();
c = m2.numRows();
d = m2.numCols();
for (i = 0; i < a; i++) {
for (j = 0; j < b; j++) {
for (k = 0; k < c; k++) {
for (l = 0; l < d; l++) {
m = i*c+k;
n = j*d+l;
m3.pp[m][n]=m1.pp[i][j]*m2.pp[k][l];
}
}
}
}
return m3; // Stroustrup 1992 page 236, 237.
}

void main()
{
Matrix<int> a(2,2);
Matrix<int> b(3,3);
Matrix<int> c(6,6);
a(0,0) = 1;
a(0,1) = 2;
a(1,0) = 3;
a(1,1) = 4;
b(0,0) = 1;
b(0,1) = 2;
b(0,2) = 3;
b(1,0) = 4;
b(1,1) = 5;
b(1,2) = 6;
b(2,0) = 7;
b(2,1) = 8;
b(2,2) = 9;
cout << a << endl;
cout << b << endl;
c=kronProd(a,b);
cout << c << endl;
Matrix<long double> e(2,2);
cin >> e;
cout << e << endl;
// Matrix<long double> f(1000,1000); // OK! on 8 MB Ram and 240 MB Harddisk
// Matrix<long double> g(10000,10000); Too large. Need more (virtual) memory??

/* How can we avoid the program to crash when too large matrices are declared.
Exception handling or other ways of testing? See C++ Report March-April 1994
page 18 and C++ Report Nov. - Dec. 1994 page 21. My personl view. Do
as much as possible testing e.g. range checking and checking for available
resources. Use termination and not resumption. See Stroustrup 1994 page
390. As a last resort use Exception Handling. Perhaps two versions of a
library should be implemented, one with exception handling and one without.
Use conditional compiling and header files to enhance portability.
*/
}
Kjell Gunnar Bleivik
Make it simple, as simple as possible but no simpler: | DigitalPunkt.no |
Post Reply