// MatrixI.H
// Given up using a Matrix<T> approach for now: too many 
// aggravating difficulties.
// News group response suggests looking at the "STL"
// I ftp'd the STL from ftp.cs.rpi.edu today (to lake-o).
// Will look at it later.

// See also the analogous int class in MatrixI.H

//	JR
//	11/3/95  Tested all functions.
//		 Added member "rows()".
//		       operators +=,+,-=,-.
//	11/4/95  Qi tested. Found error in copy constructor.
//		 Reversed order of deletion in destructor.

#ifndef MATRIXI_H
#define MATRIXI_H
#include <assert.h>

class MatrixI
{
   friend class MatrixD;
   private:
	int nrows;
	int ncols;
	int **mat;
   public:
	MatrixI()
	: nrows(0), ncols(0), mat(0)
	{}
	MatrixI(int nr,int nc);
	MatrixI(int nr,int nc,int val);
	MatrixI(int n);
	~MatrixI();
	MatrixI(const MatrixI& m);
	MatrixI& operator=(const MatrixI& m)
	{	if(&m==this) return *this;
		if(nrows!=m.nrows || ncols!=m.ncols)
		{	for(int i=0;i<nrows;i++) delete[] mat[i];
			delete[] mat;
			nrows=m.nrows;
			ncols=m.ncols;
			mat = new int*[nrows];
			for(i=0;i<nrows;i++) 
			{	mat[i] = new int[nrows];
				for(int j=0;j<ncols;j++) mat[i][j]=m.mat[i][j];
			}
		}
		else
		{	for(int i=0;i<nrows;i++) 
				for(int j=0;j<ncols;j++) 
					mat[i][j]=m.mat[i][j];
		}
		return *this;
	}
	int& operator () (int i,int j)
	{	assert( 0<=i && i<nrows && 0<=j && j<ncols );
		return mat[i][j];
	}
	const int& operator () (int i,int j) const
	{	assert( 0<=i && i<nrows && 0<=j && j<ncols );
		return mat[i][j];
	}

	int rows() const
	{ 	return nrows;
	}			

	MatrixI& operator+=(const MatrixI& m);
	MatrixI& operator-=(const MatrixI& m);

	friend MatrixI operator+(const MatrixI& a,
				 const MatrixI& b);
	friend MatrixI operator-(const MatrixI& a,
				 const MatrixI& b);
	friend MatrixI operator*(const MatrixI& a,
				 const MatrixI& b);
	friend ostream& operator << (ostream& out, const MatrixI& m);

};

MatrixI::MatrixI(int nr,int nc)
: nrows(nr), ncols(nc)
{	mat = new int*[nrows];
	for(int i=0;i<nrows;i++) 
	{	mat[i] = new int[ncols];
		for(int j=0;j<ncols;j++) mat[i][j]=0;
	}
}

MatrixI::MatrixI(int nr,int nc,int val)
: nrows(nr), ncols(nc)
{	mat = new int*[nrows];
	for(int i=0;i<nrows;i++) 
	{	mat[i] = new int[ncols];
		for(int j=0;j<ncols;j++) mat[i][j]=val;
	}
}

MatrixI::MatrixI(int n)
: nrows(n), ncols(n)
{	mat = new int*[n];
	for(int i=0;i<n;i++) 
	{	mat[i] = new int[n];
		for(int j=0;j<n;j++) mat[i][j]=0;
	}
}

MatrixI::MatrixI(const MatrixI& m)
: nrows(m.nrows), ncols(m.ncols)
{	mat = new int*[nrows];
	for(int i=0;i<nrows;i++) 
	{	mat[i] = new int[ncols];
		for(int j=0;j<ncols;j++) mat[i][j]=m.mat[i][j];
	}
}

MatrixI::~MatrixI()
{	for(int i=nrows-1;i>=0;i--) delete[] mat[i];
	delete[] mat;
}

MatrixI& MatrixI::operator+=(const MatrixI& m)
{
	assert( (nrows==m.nrows) && (ncols==m.ncols) );
	for(int i=0;i<nrows;i++)
		for(int j=0;j<ncols;j++) (*this)(i,j)+=m(i,j);
	return *this;
}

MatrixI operator+(const MatrixI& m1,const MatrixI& m2)
{
	MatrixI tmp(m1);
	return (tmp+=m2);
}

MatrixI& MatrixI::operator-=(const MatrixI& m)
{
	assert( (nrows==m.nrows) && (ncols==m.ncols) );
	for(int i=0;i<nrows;i++)
		for(int j=0;j<ncols;j++) (*this)(i,j)-=m(i,j);
	return *this;
}

MatrixI operator-(const MatrixI& m1,const MatrixI& m2)
{
	MatrixI tmp(m1);
	return (tmp-=m2);
}

MatrixI operator*(const MatrixI& a,
	 	  const MatrixI& b)
{	assert(a.ncols==b.nrows);
	MatrixI tmp(a.nrows,b.ncols);
	int* ptr;
	for(int i=0;i<a.nrows;i++)
		for(int j=0;j<b.ncols;j++)
		{	ptr=tmp.mat[i]+j;
			*ptr=0;
			for(int k=0;k<a.ncols;k++)
				(*ptr)+=a.mat[i][k]*b.mat[k][j];
		}
	return tmp;
}

ostream& operator << (ostream& out, const MatrixI& m)
{
        for(int i=0;i<m.nrows;i++)
        {       out << "[ ";
                for(int j=0;j<m.ncols-1;j++) out << m.mat[i][j] << "  ";
                if(m.ncols>0) out << m.mat[i][m.ncols-1] << " ";
                out << "]" << endl;
        }
        return out;
}  

#endif

