//matrix.cc
//brian jahns c1999
//cs252
//function definitions for the matrix class

#include <iostream.h>
#include "matrix.h"
#include <assert.h>

//output stream
ostream& operator << (ostream& os, const Matrix& matrix1)
{
for (int i=0; i < matrix1.rows; i++)
{
for (int j=0; j < matrix1.columns; j++)
os << matrix1.matrix[i][j] << " ";
os << endl;
}
return os;


//input stream
istream& operator >> (istream& is, Matrix& matrix1)
{
for (int i=0; i < matrix1.rows; i++)
for (int j=0; j < matrix1.columns; j++)
is >> matrix1.matrix[i][j];
return is;


//overloaded subtraction operator
Matrix Matrix::operator - (const Matrix& matrix1)
{

return (sub(matrix1));
}

// Takes two matrices and calculates the difference
Matrix Matrix::sub(const Matrix& matrix2)
{
Matrix result2;
double** result2matrix=allocate(rows, columns);
result2.matrix=result2matrix;
result2.rows=rows;
result2.columns=columns;

for (int i=0;i<rows;i++)
for (int j=0;j<columns;j++)
result2.matrix[i][j] = matrix[i][j] - matrix2.matrix[i][j];

return result2;
}

//overloaded multiplication operator
Matrix Matrix::operator * (const Matrix& matrix3)
{
return mult(matrix3);

}

// Takes two matrices and calculates the product, working with **'s
Matrix Matrix::mult(const Matrix& matrix4) 
{
double sum;
Matrix result4;
double** result4matrix=allocate(rows, columns);
result4.matrix=result4matrix;
result4.rows=rows;
result4.columns=columns;

for (int i=0; i < rows;i ++)
for (int j=0; j < columns; j++) 
{
sum=0.0; 
for (int k=0; k < rows;k++)
sum += matrix[i][k] * matrix4.matrix[k][j];
result4.matrix[i][j] = sum;
}
return result4;
}

//overloaded transpose operator
Matrix Matrix::operator ~ ()
{
return trans();
}

//unary command to take a matrix and transpose it (rows -> columns)
Matrix Matrix::trans()
{
Matrix result6;
double** result6matrix=allocate(columns, rows);
result6.matrix=result6matrix;
result6.rows=columns;
result6.columns=rows;

for (int j=0; j < columns; j++)
for (int i=0; i < rows; i++)
result6.matrix[j][i]=matrix[i][j];

return result6;
}

// Dynamic memory allocation for a matrix, returns pointer to pointer to
// double.
double** Matrix::allocate(int rws, int cols) {

double** matrixx = new double* [rws];
for (int i=0;i<rws;i++)
matrixx[i]=new double[cols];
assert(matrixx != NULL);
return matrixx;
}

//default constructor: creates a blank matrix
Matrix::Matrix():rows(0), columns(0), matrix(NULL){}

//constructor that seeds the matrix with row and column values
Matrix::Matrix(int rws, int cols)
{
matrix = allocate(rws, cols);
rows = rws;
columns = cols;
}

//copy constructor
Matrix::Matrix(const Matrix& matrix1)
{
matrix = allocate(matrix1.rows, matrix1.columns);
rows= matrix1.rows;
columns= matrix1.columns;

for (int i=0; i < rows; i++)
for (int j=0; j < columns; j++)
matrix[i][j]=matrix1.matrix[i][j];
}

//destructor (dynamic memory allocation)
Matrix::~Matrix()
{
for (int i=0; i<rows; i++)
delete [] matrix[i];
delete matrix;
}