#include <iostream>
#include <vector>
#include <stdlib.h>
#include <string>
#include <math.h> //fabs
/* TO BE DONE
- need to check operations perform correctly
*/
/*create a matrix input string of form [1,2,3][4,5,6][7,8,9] - or allow commas between brackets, [],[],[] (they are ignored) or add B vector - [1,2,3|1][4,5,6|2][7,8,9|3]
take input in as string and convert it to a vector<T> A and vector<T> B inside of the mtx class
if the format works (implicitly) then the matrix should read it in - otherwise it should try a different form
*/
class line;
////////////////////////////////////////////////////////////////////////////////
//CLASS MTX DEFINITION
template <class T>
class mtx
{
private:
friend class line;
std::vector<T> A; //matrix
std::vector<T> B; //solution vector - size = number of rows for matrix - not necessary for some matrix operations
std::size_t width;
std::size_t height;
std::size_t x, y;
//PRIVATE FUNCTIONS
bool isMatrixSquare(); //handles an error
void swapRows (int first_in, int second_in);
class line
{
mtx * p_mtx;
public:
line(mtx *p_mtx_in);
T& operator [] (std::size_t y_in);
const T& operator [] (std::size_t y_in) const;
};
public:
//CONSTRUCTORS
mtx ();
mtx (std::vector<T>& Ain, std::vector<T>& Bin);
//INDEX ACCESS OPERATOR OVERLOADS
line& operator [] (std::size_t index);
T& operator () (std::size_t x_in, std::size_t y_in);
const T& operator () (std::size_t x_in, std::size_t y_in) const;
//MATRIX PUBLIC FUNCTIONS
mtx operator = (mtx& in); //ASSIGNMENT OPERATOR
T& at (int i, int j);
friend void swap(mtx<T>& first_in, mtx<T>& second_in);
//UNARY FUNCTIONS
mtx& operator += (const mtx& rhs);
mtx& operator -= (const mtx& rhs);
mtx& operator *= (const mtx& rhs);
//BINARY FUNCTIONS
mtx operator + (const mtx& rhs);
mtx operator - (const mtx& rhs);
mtx operator * (const mtx& rhs);
mtx operator * (const T& rhs); //scalar multiplication
//void Apush_back (double);
//double Aat (int row, int col); //reads element at row,col where 0,0 is the first element in the matrix
//void Bpush_back (double);
//double Bat (int x);
//bool
//T determinant(); //calculates the determinant of square matrix
mtx inverse(); //returns the inverse matrix
void rref (); //Reduce Row Echelon Form - basic solution for square matrix
void print();
/*at some point more functions will be added but this should be enough for the beam calc
void inverse (void);
void eigen (void);
mtx operator* (mtx const rhs&); //A = B*C
mtx& operator*= (mtx const rhs&);
*/
private:
line m_line;
};
////////////////////////////////////////////////////////////////////////////////
//MATRIX CLASS DECLARATION
//PRIVATE FUNCTIONS*************************************************************
template <class T>
bool mtx<T>::isMatrixSquare()
{
if (width == height)
{
return true;
}
std::cerr << "ERROR at bool mtx<T>::isMatrixSquare() - matrix is not square." << std::endl;
return false;
}
template <class T>
void mtx<T>::swapRows (int row1_in, int row2_in)
{
if (row1_in >= height || row2_in >= height)
{
std::cerr <<"Error - row parameters not within matrix and vector dimension";
return;
}
T temp;
for (int i; i < width; i++)
{
temp = A[i + row1_in * width];
A[i + row1_in * width] = A[i + row2_in * width];
A[i + row2_in * width] = temp;
}
temp = B.at(row1_in); //swaps values in Bvector
B.at(row1_in) = B.at(row2_in);
B.at(row2_in) = temp;
return;
}
template <class T>
T& mtx<T>::line::operator [] (std::size_t y_in)
{
if (y_in >= p_mtx->height)
{
std::cerr << "row value is out of bounds and will be replaced with 0";
p_mtx->y = 0;
}
else
{
p_mtx->y = y_in;
}
return p_mtx->A[p_mtx->x+p_mtx->y*p_mtx->width];
}
template <class T>
const T& mtx<T>::line::operator [] (std::size_t y_in) const
{
if (y_in >= p_mtx->height)
{
std::cerr << "row value is out of bounds and will be replaced with 0";
p_mtx->y = 0;
}
else
{
p_mtx->y = y_in;
}
return p_mtx->A[p_mtx->x+p_mtx->y*p_mtx->width];
}
//MATRIX CLASS CONSTRUCTORS*****************************************************
template <class T>
mtx<T>::mtx ():A(), B(), width(0), height(0), m_line(this)
{
}
template <class T>
mtx<T>::mtx (std::vector<T>& Ain, std::vector<T>& Bin):A(Ain), B(Bin), m_line(this)
{
std::cout << "constructor started" <<std::endl;
if(Ain.size() != 0 && Bin.size() != 0 && Ain.size() % Bin.size() == 0)
{
height = Bin.size();
width = Ain.size()/height;
}
else
{
std::cerr << "Error - Matrix A and Vector B are of incompatible sizes - dummy matrix created";
A.clear();
B.clear();
}
}
//MATRIX CLASS ACCESS OPERATOR OVERLOADS****************************************
template <class T>
typename mtx<T>::line& mtx<T>::operator [] (std::size_t x_in)
{
if (x_in >= width)
{
std::cerr << "row coordinate is out of bounds - setting to 0";
x = 0;
}
else
{
x = x_in;
}
return m_line;
}
template <class T>
T& mtx<T>::operator () (std::size_t x_in, std::size_t y_in)
{
return A[x_in + y_in * width];
}
template <class T>
const T& mtx<T>::operator () (std::size_t x_in, std::size_t y_in) const
{
return A[x_in + y_in * width];
}
//MATRIX CLASS - UNARY FUNCTION OVERLOADS
template <class T>
mtx<T>& mtx<T>::operator += (const mtx& rhs)
{
if (height != rhs.height || width != rhs.width)
{
std::cerr << "ERROR at mtx& mtx<T>::operator += (const mtx& rhs) - matrix sizes do not match. No addition performed." << std::endl;
return *this;
}
for (int i = 0; i<= A.size(); i++)
{
A[i] += rhs.A[i];
}
return *this;
}
template <class T>
mtx<T>& mtx<T>::operator -= (const mtx& rhs)
{
if (height != rhs.height || width != rhs.width)
{
std::cerr << "ERROR at mtx& mtx<T>::operator -= (const mtx& rhs) - matrix sizes do not match. No subtraction performed." << std::endl;
return *this;
}
for (int i = 0; i<= A.size(); i++)
{
A[i] -= rhs.A[i];
}
return *this;
}
template <class T>
mtx<T>& mtx<T>::operator *= (const mtx& rhs)
{
if (width != rhs.height)
{
std::cout << "ERROR at mtx& mtx<T>::operator *= (const mtx& rhs) - matrix sizes are not compatible. No multiplication performed." << std::endl;
return *this;
}
//create new matrix then swap with this
std::vector<T> Atemp;
std::vector<T> Btemp(0,height);
for (int j = 0; j < height; j++)//use j for height in this and width in rhs
{
for (int i = 0; i < rhs.width; i++)
{
T mtxValue = 0;
for (int n = 0; n < width; n++)
{
mtxValue += A[n+j*width] * rhs(i,n);
}
Atemp.push_back (mtxValue);
}
}
mtx<T> temp(Atemp, Btemp);
//swap(*this, temp);
return temp;
}
template <class T>
T& mtx<T>::at (int x_in, int y_in)
{
return this->A.at(x_in + y_in * width);
}
template <class T>
void mtx<T>::rref ()
{
//WHAT HAPPENS WHEN WE HAVE MORE COLUMNS THAN ROWS?
//MORE ROWS THAN COLUMNS?
//WHEN A COLUMN DOESNT HAVE A 1 ON THE DIAGONAL
if(A.size() == 0 || B.size() == 0 || A.size() % B.size() != 0)
{
std::cerr << "ERROR at [void mtx<T>::rref ()] - Matrix A and Vector B are of incompatible sizes - RREF not performed";
return;
}
T largest, coefficient;
int largestRow, count;
count = 0;
for (int i = 0; i< width; i++) //iterate through each column
{
largest = 0;
for (int j = count; j < height; j++) //find largest in each row
{
if (fabs(A[i + j * width]) > largest)
{
largest = fabs(A[i + j * width]);
largestRow = j;
}
}
if (largestRow != count) //not on the diagonal then swap it onto the diagonal
{
this->swapRows(largestRow, count);
}
if (i != height && largest != 0) //if largest is 0 then skip
{
for (int k = 0; k < height; k++) //iterate through rows and 0 out column
{
if (k != count) //skip over diagonal
{
coefficient = -A[i + k * width]/A[i + i * width];
std::cout << "coefficient = " << coefficient << std::endl;
A[i + k * width] = 0; //first coefficient is 0 - no need to calc
for (int m = i + 1; m < width; m++) //iterate across width
{
A[m + k * width] += A[m + i * width] * coefficient;
}
B[k] += B[i] * coefficient;
}
}
this->print();
}
if (A[i + i * width] != 0) //set diagonal value to 1
{
coefficient = 1.0 / A[i + i * width];
A[i + i * width] = 1.0;
for (int n = i + 1; n < width; n++)
{
A[n + i * width] *= coefficient;
}
B[i] *= coefficient;
count++;
if (count == width || count == height)
{
return;
}
}
}
}
template <class T>
mtx<T>::line::line (mtx * p_mtx_in):p_mtx(p_mtx_in)
{
}
template <class T>
void swap (mtx<T>& first_in, mtx<T>& second_in)
{
using std::swap;
swap(first_in.A, second_in.A);
swap(first_in.B, second_in.B);
swap(first_in.width, second_in.width);
swap(first_in.height, second_in.height);
swap(first_in.x, second_in.x);
swap(first_in.y, second_in.y);
swap(first_in.m_line, second_in.m_line);
return;
}
template <class T>
void mtx<T>::print ()
{
for (int j=0; j<height; j++)
{
for (int i = 0; i<width; i++)
{
std::cout << A[i + j * width] << " ";
}
std::cout << "| " << B[j] << std::endl;
}
}
int main() {
// your code goes here
std::vector<double> atemp, btemp;
for (int i = 0; i < 12; i++)
{
atemp.push_back(double(pow(i,3)/4.12785));
}
for (int i = 0; i < 3; i++)
{
btemp.push_back(double(4.0-i));
}
mtx<double> M (atemp, btemp);
M.print();
M *= M;
M.rref();
M.print();
double pi = 3.14159;
M [1][2] = pi;
M(0,1) = pi;
M.print();
M.rref();
M.print();
return 0;
}