Matrix determinant in template using gaussian elimination - c++

I'm having issues to implement the determinant of a matrix inside my matrix template. I'm trying to obtain the determinant by calculating the product of the principal diagonal in the reduced associated matrix. The problem is that it only works for some cases and is not reliable. This is the code for the determinant
template <typename T>
T Matrix<T>::Det() const {
if (Rows != Cols) {
cout << "Matrix must be square" << endl;
}
Matrix<T> r = Reduced();
T Det = 1;
for (int i=0; i<Rows; i++) {
Det *= r.getValue(i, i);
}
return Det;
}
Since the Gaussian elimination works, the reduced matrix that I obtain for any given matrix (which fits the criteria to be reduced) is fine, so i thought there wouldn't be any issue, but I haven't been able to see what I'm missing.
Any advice will be welcomed!
Edit:
As someone pointed out, here is a minimal reproducible example.
This would be the template
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
#include <iostream>
using namespace std;
template <typename T>
class Matrix {
private:
unsigned int Rows;
unsigned int Cols;
T *Mat;
public:
Matrix(unsigned int Dim);
Matrix(unsigned int Rows, unsigned int Cols);
Matrix(unsigned int Rows, unsigned int Cols, const std::vector<T>& Vec);
Matrix(unsigned int Dim, const std::vector<T>& Vec);
Matrix(const Matrix<T>& M);
~Matrix();
T& getValue(unsigned int Row, unsigned int Col) const;
T Det() const;
Matrix<T> Reduced() const;
};
template <typename T>
Matrix<T>::Matrix(unsigned int Rows, unsigned int Cols)
: Rows(Rows), Cols(Cols) {
if (Rows<=0 || Cols<=0) {
cout << "Número inválido de filas o columnas" << endl;
}
Mat = new T[Rows*Cols];
for (int i=0; i<Rows*Cols; i++) {
Mat[i] = 0;
}
}
template <typename T>
Matrix<T>::Matrix(unsigned int Dim)
: Rows(Dim), Cols(Dim) {
if(Rows<=0 || Cols<=0) {
cout << "Número inválido de filas o columnas" << endl;
}
Mat = new T[Rows*Cols];
for (int i=0; i<Rows*Cols; i++) {
Mat[i] = 0;
}
}
template <typename T>
Matrix<T>::Matrix(unsigned int Rows, unsigned int Cols, const std::vector<T>& Vec)
: Rows(Rows), Cols(Cols) {
if (Rows<=0 || Cols<=0) {
cout << "Número inválido de filas o columnas" << endl;
}
Mat = new T[Rows*Cols];
if (Vec.size() != Rows*Cols) {
cout << "Los tamaños de la matriz y el vector no son iguales" << endl;
}
for (int i=0; i<Rows*Cols; i++) {
Mat[i] = Vec[i];
}
}
template <typename T>
Matrix<T>::Matrix(unsigned int Dim, const std::vector<T>& Vec)
: Rows(Dim), Cols(Dim) {
if (Rows<=0 || Cols<=0) {
cout << "Número inválido de filas o columnas" << endl;
}
Mat = new T[Rows*Cols];
if (Vec.size() != Rows*Cols) {
cout << "Número inválido de filas o columnas" << endl;
}
for (int i=0; i<Rows*Cols; i++) {
Mat[i] = Vec[i];
}
}
template <typename T>
Matrix<T>::Matrix(const Matrix<T>& M)
: Rows(M.Rows), Cols(M.Cols), Mat(new T[Rows * Cols]) {
for (int i = 0; i < Rows * Cols; i++)
Mat[i] = M.Mat[i];
}
template <typename T>
Matrix<T>::~Matrix() {
delete[] Mat;
}
template <typename T>
T &Matrix<T>::getValue(unsigned int Row, unsigned int Col) const {
if (Row<0 || Row>=Rows || Col<0 || Col>=Cols) {
cout << "Índice incorrecto" << endl;
}
return Mat[Row*Cols + Col];
}
template <typename T>
Matrix<T> Matrix<T>::Reduced() const {
if (Rows != Cols) {
cout << "La matriz debe ser cuadrada para reducirse" << endl;
}
Matrix<T> Tri(*this);
int n = Rows;
int m = 0;
for (int k=0; k<n-1; k++) {
if (Tri.Mat[k*Cols + k] == 0)
cout << "La matriz es singular" << endl;
for (int i = k+1; i<n; i++) {
m = Tri.Mat[i*Cols + k]/Tri.Mat[k*Cols + k];
for (int j = k+1; j<n; j++) {
Tri.Mat[i*Cols + j] = Tri.Mat[i*Cols + j] - m*Tri.Mat[k*Cols + j];
}
Tri.Mat[i*Cols + k] = 0;
}
}
return Tri;
}
template <typename T>
T Matrix<T>::Det() const {
if (Rows != Cols) {
cout << "Matrix must be square" << endl;
}
Matrix<T> r = Reduced();
T Det = 1;
for (int i=0; i<Rows; i++) {
Det *= r.getValue(i, i);
}
return Det;
}
template <class T>
ostream & operator<<(ostream &os, const Matrix<T> &Shw) {
for (int i=0; i<Shw.getRows(); i++) {
os << "| ";
for (int j=0; j<Shw.getCols(); j++) {
os << Shw.getValue(i,j) << " ";
}
os << "|\n";
}
return os;
}
#endif
This is the implementation on main.cc
#include "matrix.h"
int main() {
Matrix<double> M1(2, 2, {1, 3, 5, 7});
cout << M1.Det() << endl;
Matrix<double> M2(3, 3, {1, 3, 5, 7, 8, 9, 11, 2, 14});
cout << M2.Det() << endl;
return 0;
}
And the output is the following
-8 //This one is okay
-143 //This one is not

After a little inspection, I think I've found your problem.
You've made a simple mistake defining one of your key variables m. This is as you know, the main scaler in Gaussian elimination, and its job is to zero out the next row's element.
Instead of defining it as int m = 0 you should've defined it as float m = 0 or double m = 0.
Also, in the line that you calculate m you need to force cast the operands of the division to the appropriate types. So after redefining m, you should change this line:
m = Tri.Mat[i*Cols + k]/Tri.Mat[k*Cols + k]
to this
m = Tri.Mat[i*Cols + k] / (double)Tri.Mat[k*Cols + k]
Keep in mind that you're template type should be double as well or again this will not work.
Also, I recommend you to take a look at here to understand some of Gaussian Elimination's limits. There are some cases in which the algorithm will not work effectively.

Related

Error in implementation of Matrix multiplication using template classes

I got a homework which looks something like this. I am working on it and hold beginner knowledge of the same.
I have to create a header file that contains this code and then use the header file to get the desired results.
I am working with C++ template, and operator overloading.
#include <iostream>
#include <memory>
#include "matrix.h"
#include "symetric_matrix.h"
using namespace std;
int main()
{
const Matrix<int, 3, 2> m1; // Creates 3*2 matrix, with all the default elements set to 0;
cout << m1 << endl;
Matrix<int, 3, 3> m2(4); // Creates 3*3 matrix, with the default elements equals to 4;
cout << m2 << endl;
const Matrix<int, 3, 3> m3 = m2; // C-py constructor may take O(MN) and not O(1).
cout << m3 << endl;
// min() returns the minimal value in the matrix.
if (min(m1) < min(m3))
cout << "Min value of m3(" << min(m3) << ") is bigger than min value of m1(" << min(m1) << ")" << endl;
if (m1.avg() < m3.avg()) // Compares the average of the elements
cout << "Average value of m3(" << m3.avg() << ") is bigger than average value of m1(" << m1.avg() << ")" << endl;
m2(0, 0) = 13;
cout << m2[0][0] << " " << m2[1][0] << endl; // Should print "13 4"
try
{
cout << m2 + m3 << endl;
cout << m3 * m1 << endl; // You can choose the format of matrix printing;
cout << m1 * m2; // This should throw an exception
}
catch (const Matrix<int, 3, 2>::IllegalOperation &e)
{
cout << e.what() << endl;
}
Matrix<int, 3, 3> m4;
m4 = m3;
cout << m4 << endl;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
m4(i, j) = i + j;
cout << m4 << endl;
cout << "m4[1][1] = " << m4[1][1] << endl;
cout << "m4[1][1] = " << m4(1, 1) << endl; // m4(1,1) same result as m4[1][1]
Matrix<int, 3, 3> m5(3);
m5 = 2 * m4;
cout << m5 << endl;
Matrix<int, 3, 3> m6(m4);
cout << m6 << endl;
m5 += m4;
cout << m5 << endl;
if (m6 != m5)
cout << "m6 != m5" << endl;
Matrix<Matrix<int, 3, 2>, 4, 4> composite(m1); // Creates matrix, where each element is m1;
cout << composite;
unique_ptr<Matrix<int, 3, 3>> symetric_matrix(new SymetricMatrix<int, 3>(5)); // SymetricMatrix matrix 3*3 with default element equals to 5;
(*symetric_matrix)(1, 2) = 8;
cout << (*symetric_matrix)(1, 2) << " " << (*symetric_matrix)(2, 1) << endl; // Should print "8 8"
cout << (*symetric_matrix)[1][2] << " " << (*symetric_matrix)[2][1] << endl; // Should print "8 8"
(*symetric_matrix)[1][0] = 18;
cout << (*symetric_matrix)[1][0] << " " << (*symetric_matrix)[0][1] << endl; // Should print "18 18"
return 0;
}
My Updated solution for now.
template <class T, int M, int N>
class Matrix
{
private:
T mat[M][N];
int rows = M;
int cols = N;
public:
// constructor
Matrix(int v = 0)
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
mat[i][j] = v;
}
}
T &operator()(int i, int j)
{
return mat[i][j];
};
T *operator[](int index)
{
return mat[index];
};
// << overloading
friend std::ostream &operator<<(std::ostream &os, const Matrix<T, M, N> &L)
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
os << L.mat[i][j] << " ";
os << "\n";
}
return os;
};
template <class T1, int M1, int N1>
Matrix<T, M, M> operator*(Matrix<T1, M1, N1> const &other);
Matrix<T, M, M> operator+(Matrix<T, M, N> const &other);
friend T min(Matrix obj)
{
T result = obj.mat[0][0];
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
if (result < obj.mat[i][j])
result = obj.mat[i][j];
}
return result;
};
long double avg() const
{
long double result = 0;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
if (result < mat[i][j])
result = result + mat[i][j];
}
return result / (M * N);
}
};
template <class T, int M, int N>
Matrix<T, M, M> Matrix<T, M, N>::operator+(Matrix const &other)
{
if ((this->rows == other.rows) && (this->cols == other.cols))
{
Matrix<T, M, N> resultantMatrix;
for (auto i = 0; i < this->rows; i++)
{
for (auto j = 0; j < this->cols; j++)
{
auto &valueFirst = this->mat[i][j];
auto &valueSecond = other.mat[i][j];
// if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
// throw std::out_of_range("Resultant value of matrix is out of range");
// else
resultantMatrix(i, j) = valueFirst + valueSecond;
}
}
return resultantMatrix;
}
else
throw std::runtime_error("Matrices cannot be added, sizes do not match");
}
template <class T, int M, int N>
template <class T1, int M1, int N1>
Matrix<T, M, M> Matrix<T, M, N>::operator*(Matrix<T1, M1, N1> const &other)
{
if ((this->rows == other.rows) && (this->cols == other.cols))
{
Matrix<T, M, N> resultantMatrix;
for (auto i = 0; i < this->rows; i++)
{
for (auto j = 0; j < this->cols; j++)
{
for (auto k = 0; k < this->cols; k++)
{
auto &valueFirst = this->mat[i][k];
auto &valueSecond = other(k, j);
// if ((additionOverflow(valueFirst, valueSecond)) || (additionUnderflow(valueFirst, valueSecond)))
// throw std::out_of_range("Resultant value of matrix is out of range");
// else
resultantMatrix(i, j) += valueFirst * valueSecond;
}
}
}
return resultantMatrix;
}
else
throw std::runtime_error("Matrices cannot be added, sizes do not match");
}
I am getting an error and I don't understand why.
error: no match for call to ‘(const Matrix<int, 3, 2>) (int&, int&)’
112 | auto &valueSecond = other(k, j);
| ~~~~~^~~~~~
matrix.h:20:8: note: candidate: ‘T& Matrix<T, M, N>::operator()(int, int) [with T = int; int M = 3; int N = 2]’ (near match)
20 | T &operator()(int i, int j)
| ^~~~~~~~
matrix.h:20:8: note: passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers
It only happens at this line auto &valueSecond = other(k, j); and not this one resultantMatrix(i, j) += valueFirst * valueSecond;, Why?
I just need help with the whole program while I try and learn!
Any help is appreciated.
As for the error message
matrix.h:20:8: note: passing ‘const Matrix<int, 3, 2>*’ as ‘this’ argument discards qualifiers
other is const Matrix<int, 3, 2>&. The T &operator()(int i, int j) is implemented for non const Matrix<int, 3, 2>&. There should be provided two versions of the operators
T &operator()(int i, int j)
{
return mat[i][j];
};
const T &operator()(int i, int j) const
{
return mat[i][j];
};
T *operator[](int index)
{
return mat[index];
};
const T *operator[](int index) const
{
return mat[index];
};
Using operator() as a subscript operator may be confusing. It should be
T &operator[](int i, int j)
{
return mat[i][j];
};
const T &operator[](int i, int j) const
{
return mat[i][j];
};
Subscript operators usually are defined for size_t types.

Can someone find the syntax error in this program

I have written a c++ program to check whether a matrix is sparse or not. The syntax errors which come up are as follows:
main.cpp:56:8: error: deduced class type ‘matrix’ in function return type
matrix matrix <T>::add(matrix r)
^~~~~~~~~~
main.cpp:11:7: note: ‘template class matrix’ declared here
class matrix
^~~~~~
main.cpp:56:8: error: prototype for ‘matrix matrix::add(matrix)’ does not match any in class ‘matrix’
matrix matrix <T>::add(matrix r)
^~~~~~~~~~
main.cpp:19:9: error: candidate is: matrix matrix::add(matrix&)
matrix add(matrix&);
^~~*
And the program is:
#include<iostream>
#include <exception>
using namespace std;
class mismatchDimension:public exception
{
public:
void error_Msg () const;
};
template < class T >
class matrix
{
int row;
int col;
T ele[10][10];
public:
void get ();
bool check_Sparse ();
matrix add (matrix &);
void print ();
};
//no changes to be made to the above code
void mismatchDimension::error_Msg () const const //Error printing method
{
cout << "Dimension of matrices do not match" << endl;
}
template < class T >
void matrix < T >::get () //Element input of matrix
{
cin >> row;
cin >> col;
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
cin >> ele[j][i];
}
}
template < class T >
bool matrix < T >::check_Sparse () //Check if the matrix is sparse
{
int i, j, t;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (ele[j][i] == 0) ++t;
}
}
if (t > (row * col) / 2) return true;
else return false;
}
template < class T >
matrix matrix < T >::add (matrix r) //Addition of the matrices
{
mismatchDimension z;
int i, j;
matrix < T > w;
if (row != r.row && col != r.col) throw z;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
w.ele[j][i] = ele[j][i] + r.ele[j][i];
}
}
return w;
}
template < class T >
void matrix < T >::print () //printing the matrix
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++) cout << ele[j][i] << endl;
}
}
// no changes to be made below
int
main ()
{
matrix < int >m1, m2, m3;
m1.get ();
m2.get ();
try
{
m3 = m1.add (m2);
m3.print ();
} catch (mismatchDimension & m)
{
m.error_Msg ();
}
if (m1.check_Sparse ())
cout << "Matrix is sparse" << endl;
else
cout << "Matrix is not sparse" << endl;
}
There are multiple issues:
In the declaration matrix add (matrix &); you pass by reference while in the definition matrix matrix < T >::add (matrix r) you pass by value. Choose only one.
The return type specification and the parameter type should be provided with template argument:
template <class T>
matrix<T> matrix<T>::add (matrix r)
{
...
}
Note that since C++11, you can also omit template argument in the return type with trailing return type declaration:
template <class T>
auto matrix<T>::add (matrix r) -> matrix
{
...
}

How to properly implement a copy constructor for a dynamic Matrix?

I have a Matrix (Matriz) class implemented as following:
Header:
#ifndef MATRIZ_H
#define MATRIZ_H
class Matriz
{
public:
Matriz(unsigned int nL, unsigned int nC);
~Matriz();
Matriz& operator+=(const Matriz &ptr);
const Matriz operator+(const Matriz &ptr) const;
Matriz* subtracaoMatriz(Matriz *m);
Matriz* multiplicacaoMatriz(Matriz *m);
void inserirMatriz();
void imprimirMatriz();
int verificaOperacao(const Matriz& ptr);
Matriz& operator-=(const Matriz &ptr);
const Matriz operator-(const Matriz &ptr) const;
const Matriz operator*(const Matriz &ptr) const;
protected:
private:
unsigned int nLinhas;
unsigned int nColunas;
int** matrix;
int verificaOperacao(Matriz *m); //0 -> cannot make the operation; 1 -> OK for product; 2 -> OK for sum;
};
#endif // MATRIZ_H
Implementation:
#include "Matriz.h"
#include <iostream>
using namespace std;
Matriz::Matriz(unsigned int nL, unsigned int nC)
{
this->nLinhas = nL;
this->nColunas = nC;
this->matrix = new int*[nLinhas];
for (unsigned int i = 0; i < nLinhas; ++i)
this->matrix[i] = new int[nColunas];
for(unsigned int i = 0; i < nLinhas; i++)
for(unsigned int j = 0; j < nColunas; j++)
this->matrix[i][j] = 0;
}
Matriz::~Matriz()
{
//dtor
}
int Matriz::verificaOperacao(Matriz *m)
{
if((this->nLinhas == m->nLinhas) && (this->nColunas == m->nColunas))
return 2;
else if(this->nColunas == m->nLinhas)
return 1;
else
return 0;
}
int Matriz::verificaOperacao(const Matriz& ptr)
{
if((this->nLinhas == ptr.nLinhas) && (this->nColunas == ptr.nColunas))
return 2;
else if(this->nColunas == ptr.nLinhas)
return 1;
else
return 0;
}
Matriz& Matriz::operator+=(const Matriz &ptr) {
if(this->verificaOperacao(ptr) == 2)
{
for(unsigned int i = 0; i < this->nLinhas; i++)
for(unsigned int j = 0; j < this->nColunas; j++)
this->matrix[i][j] = this->matrix[i][j] + ptr.matrix[i][j];
return *this;
}
else
return *this;
}
const Matriz Matriz::operator+(const Matriz &ptr) const {
Matriz resultado = *this;
resultado += ptr;
return resultado;
}
Matriz& Matriz::operator-=(const Matriz &ptr) {
if(this->verificaOperacao(ptr) == 2)
{
for(unsigned int i = 0; i < this->nLinhas; i++)
for(unsigned int j = 0; j < this->nColunas; j++)
this->matrix[i][j] = this->matrix[i][j] - ptr.matrix[i][j];
return *this;
}
else
return *this;
}
const Matriz Matriz::operator-(const Matriz &ptr) const {
Matriz resultado = *this;
resultado -= ptr;
return resultado;
}
const Matriz Matriz::operator*(const Matriz &ptr) const {
Matriz *resultado = new Matriz(this->nLinhas, ptr.nColunas);
for(unsigned i = 0; i < this->nLinhas; i++)
{
for(unsigned j = 0; j < ptr.nColunas; j++)
for(unsigned int aux = 0; aux < ptr.nColunas; aux++)
resultado->matrix[i][j] += this->matrix[i][aux] * ptr.matrix[aux][j];
}
return *resultado;
}
void Matriz::inserirMatriz()
{
for(unsigned int i = 0; i < this->nLinhas; i++)
for(unsigned int j = 0; j < this->nColunas; j++)
cin >> this->matrix[i][j];
}
void Matriz::imprimirMatriz()
{
for(unsigned int i = 0; i < this->nLinhas; i++) {
for(unsigned int j = 0; j < this->nColunas; j++)
cout << this->matrix[i][j] << "\t";
cout << endl;
}
}
Main:
#include <iostream>
#include "Matriz.h"
using namespace std;
int main()
{
Matriz *m1 = new Matriz(2, 2);
Matriz *m2 = new Matriz(2, 2);
m1->inserirMatriz();
m2->inserirMatriz();
cout << "Matrix 1:" << endl;
m1->imprimirMatriz();
cout << "Matrix 2:" << endl;
m2->imprimirMatriz();
Matriz m3 = *m1 + *m2;
cout << "The sum is: " << endl;
m3.imprimirMatriz();
cout << "The subtraction is: " << endl;
Matriz m4 = *m1 - *m2;
m4.imprimirMatriz();
cout << "The product is: " << endl;
Matriz m5 = *m1 * *m2;
m5.imprimirMatriz();
///HERE LIES THE PROBLEM
m2 = m1;
cout << "m2 = m1" << endl;
cout << "m2:" << endl;
m2->imprimirMatriz();
cout << "*m1 += *m2" << endl;
cout << "m2:" << endl;
*m1 += *m2;
m2->imprimirMatriz();
delete m1;
delete m2;
return 0;
}
I believe that the issue is caused by the default copy constructor, however I tried without success to implement one.
There are two ways to implement a copy constructor:
Method 1
Use a std::vector instead of dynamic memory, this approach eliminates the need for a custom copy constructor and removes the risk of memory leaks, see here. I'm not going to rewrite your code but do some simple stuff to illustrate the point:
// Header file
#include <vector>
class Matriz
{
...
private:
std::vector<std::vector<int>> matrix;
}
// CPP file
Matriz::Matriz(unsigned int nL, unsigned int nC)
{
matrix.resize(nL, std::vector<int>(nC, 0));
// You can now access items with matrix[x][y].
}
This method with vectors works because when you want to copy your Matriz class the copy constructors for the vector will automatically be called. It's all done for you.
Method 2
If you still want to use dynamic memory then you need to implement a deep copy constructor:
//Header file.
class Matriz
{
...
Matriz(const Matriz& m);
}
// CPP file
Matriz::~Matriz() { delete[] matrix; } // DO NOT FORGET THIS!!!
Matriz::Matriz(const Matriz& m)
{
delete[] matrix;
// Create the dynamic memory.
int** matrix = new int*[m.nLinhas];
for(int i = 0; i < m.nLinhas; ++i)
matrix[i] = new int[nColunas];
nLinhas = m.nLinhas;
nColunas = m.Colunas;
// Copy over the data.
for(int l = 0; l < nLinhas; l++)
{
for(int c = 0; c < nColunas; c++)
{
matrix[l][c] = m.matrix[l][c];
}
}
}
You can follow the same concepts for the assignment operator operator=. I would suggest using the vector if you can, this will eliminate any possible leak issues and given what you are doing there won't be any speed loss issues.

_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)) error

I'm trying to figure out why my program fails when I run. So far when I run my program it fails on me. I debugged the error and it brings me to dbgdel.cpp. Line 32 " _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));". I've searched for the answer to no avail, but it has something to do with my memory leak?
Here is my header:
#include <iostream>
using namespace std;
namespace project
{
#ifndef MATRIX_H
#define MATRIX_H
typedef int* IntArrayPtr;
class Matrix
{
public:
friend ostream& operator<<(ostream& out, Matrix& object);
//friend istream& operator>>(istream& in, Matrix& theArray);
//Default Constructor
Matrix();
Matrix(int max_number_rows, int max_number_cols, int intial_value);
//Destructor
~Matrix();
//Copy Constructor
Matrix(const Matrix& right_side);
//Assignment Operator
Matrix& operator=(const Matrix& right_side);
void Clear();
int Rows();
int Columns();
bool GetCell(int x,int y, int& val);
bool SetCell(int x,int y, int val);
int getNumber(int r, int c);
//void Debug(ostream& out);
private:
int initialVal;
int rows;
int cols;
IntArrayPtr *m;
};
#endif
}
My implementation file:
#include <iostream>
#include "Matrix.h"
using namespace project;
using namespace std;
namespace project
{
Matrix::Matrix()
{
typedef int* IntArrayPtr;
IntArrayPtr *m = new IntArrayPtr[1];
for(int i = 0; i < 1; i++)
m[i] = new int[1];
for(int r = 0; r < 1; r++)
for(int c = 0; c < 1;c++)
m[r][c] = 0;
}
Matrix::Matrix(int max_number_rows, int max_number_cols, int initial_value)
{
initialVal = initial_value;
rows = max_number_rows;
cols = max_number_cols;
IntArrayPtr *m = new IntArrayPtr[rows];
for(int i = 0; i < rows; i++)
m[i] = new int[cols];
for(int r = 0; r < max_number_rows; r++)
for(int c = 0; c < max_number_cols;c++)
m[r][c] = initial_value;
}
Matrix::~Matrix()
{
for(int i = 0; i <= rows; i++)
delete [] m[i];
delete [] m;
}
void Matrix::Clear()
{
for(int r = 0; r < rows; r++)
for(int c = 0; c < cols;c++)
m[r][c] = initialVal;
}
int Matrix::Rows()
{
return rows;
}
int Matrix::Columns()
{
return cols;
}
bool Matrix::GetCell(int x,int y, int& val)
{
if(x < rows || y < cols)
return false;
else
{
val = m[x - 1][y - 1];
return true;
}
}
bool Matrix::SetCell(int x, int y, int val)
{
if(x < rows || y < cols)
return false;
else
{
m[x - 1][y - 1] = val;
return true;
}
}
int Matrix::getNumber(int r, int c)
{
return m[r][c];
}
ostream& operator<<(ostream& out, Matrix& object)
{
for(int r = 0; r < object.rows; r++)
{
for(int c = 0; c < object.cols; c++)
{
out << " " << object.m[r][c];
}
out << endl;
}
return out;
}
Matrix& Matrix::operator=(const Matrix& right_side)
{
if (this != &right_side)
{
rows = right_side.rows;
cols = right_side.cols;
delete[] m;
IntArrayPtr *m = new IntArrayPtr[rows];
for(int i = 0; i < rows; i++)
m[i] = new int[cols];
for(int r = 0; r < rows; r++)
for(int c = 0; c < cols;c++)
m[r][c] = right_side.initialVal;
}
return *this;
}
/*
void Matrix::Debug(ostream& out)
{
out << "Number of rows = " << rows << endl;
out << "Number of columns = " << cols << endl;
out << "Initializer = " << initialVal << endl;
out << "Current contents of the matrix: " << endl;
out << m << endl;
}
*/
/*
istream& operator >>(istream& in, Matrix& theArray)
{
in >>
}
void interfaceMatrix()
{
int userChoice, rows, columns, value;
cout << "Default matrix or custom(1 for default, 0 for custom): ";
cin >> userChoice;
if (userChoice == 1)
{
Matrix object;
return object;
}
else if(userChoice == 0)
{
cout << "Enter number of rows: ";
cin >> rows;
cout << "Enter number of columns: ";
cin >> columns;
cout << "Enter initial value of each element: ";
cin >> value;
if(rows <= 0 || columns <= 0)
{
cout << "Invalid input." << endl;
exit(1);
}
else
{
Matrix object(rows, columns, value);
return object;
}
}
else
{
cout << "Invalid choice." << endl;
exit(1);
}
}
*/
}
In my driver I just put Matrix test(2,2,2), so I can create a 2 x 2 array with initial value of 2 for each element. I get the above error.
You are allocating rows number of rows, but deallocating rows+1 number of rows.
Check the destructor. <= must be <.
Besides this there are a lot of other [potential] errors in your code:
you are setting the local m variable instead of setting the m data member of your class (that's why I have the convention to always precede data members by m_ to prevent this kind of confusion). This error appears both in the constructor and the assignment operator.
you use rows to allocate the matrix, but max_number_rows to initialize the matrix. Although it works correctly now, it may lead to errors if row is initialized differently later (e.g. if row is initialized with std::max(max_number_rows,1000). Your code in the assignment operator is better.
your if-test in GetCell and SetCell is incorrect. It should probably be >= instead of <
the assignment operator copies the size of the matrix, but assigns all cells an initialValue. This is not an assignment. This implementation might/will confuse the rest of the code.
the typedef of IntArrayPtr is unnecessary
two issues:
You are not allocating any value into the "m" member of your object, you are allocating into local variables named "m"
you are over deallocating by looping from i=0 to i <= rows, you want i=0 to i < rows

Overloading << operator results in no output

I am not sure if I am correctly overloading the << operator. The following code compiles without problem but does not produce the expected output.
#include <iostream>
#include "Matrix.h"
template<class T>
std::ostream& operator<<(std::ostream &out, const matrix<T> &A)
{
for(int ii = 0; ii << A.size(1); ii++)
{
for(int jj = 0; jj < A.size(2); jj++)
{
out << A(ii,jj) << " ";
}
out << std::endl;
}
return out;
}
int main(int argc, char** argv)
{
matrix<double> A = {{1.0, 2.0},{1.0,-1.0}};
cout << "\"" << A << "\"\n";
return 0;
}
The only output is:
""
Matrix.h
template<class T>
class matrix
{
public:
matrix(int rows, int cols);
matrix(const std::initializer_list<std::initializer_list<T>>& lst);
T& operator()(int i, int j);
T operator()(int i, int j) const;
int size(int n) const;
private:
int mRows;
int mCols;
std::vector<T> mData;
};
template<class T>
matrix<T>::matrix(int rows, int cols)
: mRows(rows),
mCols(cols),
mData(rows * cols)
{
}
template<class T>
matrix<T>::matrix(const std::initializer_list<std::initializer_list<T> >& lst)
: matrix(lst.size(), lst.size() ? lst.begin()->size() : 0)
{
int ii = 0, jj = 0;
for(const auto& l : lst)
{
for(const auto& v : l)
{
mData[ii*mCols + jj] = v;
jj++;
}
jj = 0;
ii++;
}
}
template<class T>
T& matrix<T>::operator()(int i, int j)
{
return mData[i*mCols + j];
}
template<class T>
T matrix<T>::operator()(int i, int j) const
{
return mData[i*mCols + j];
}
template<class T>
int matrix<T>::size(int n) const
{
if(n == 1)
{
return mRows;
}
else if(n == 2)
{
return mCols;
}
}
In your first for loop, you have:
for(int ii = 0; ii << A.size(1); ii++)
^
That should be a single < character:
for(int ii = 0; ii < A.size(1); ii++)
^
The reason why it wasn't doing anything is because the original loop resulted in a condition of 0 << A.size(1), which is 0, or false; thus, the outer loop is never executed.