My Matrx class is defined as
class Matrx
{
double A[50][50];
int m,n;
public:
Matrx(void);
Matrx(int a, int b)
{
m=a;
n=b;
}
Matrx operator +(Matrx b);
Matrx Transpose(Matrx b);
Matrx operator *(Matrx b);
CString printMatrx();
void readMatrx(double a[][]);
Matrx TransposeMat(Matrx b);
};
void Matrx::readMatrx(double a[][])
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=a[i][j];
}
}
The intellisense gives error like the below
1 IntelliSense: an array may not have elements of this type d:\bmadaptive_dd_v1.02\matrx.h 17 27 TestServer
Why?
How to pass a two dimensional array as argument of the function?
The problem is that when passing multidimensional arrays as parameters in C++, you must specify the dimension of the outermost array. For example:
void ThisIsIllegal(int arr[][]); // Wrong!
void ThisIsAlsoIllegal(int arr[10][]); // Also wrong
void ThisIsLegal(int arr[][10]); // Okay
If you want to be able to have a function that takes in an array of any size, you can use templates:
template <size_t N, size_t M>
void ThisIsAlsoLegal(int (&arr)[M][N]);
This last version accepts any multidimensional array of the right type, and is probably what you're looking for.
You need to properly learn about arrays and pointers. This includes the lesson "huh! They are not as useful as I thought they were". After you've gotten familiar with how arrays and pointers work exactly you should rethink your design.
For example, in my opinion, the following design has lots of advantages:
#ifndef MATRIX_HPP_INCLUDED
#define MATRIX_HPP_INCLUDED
#include <vector>
#include <algorithm>
class matrix
{
public:
typedef std::vector<double>::size_type st;
matrix() : rows_(0), cols_(0) {}
matrix(int r, int c) : rows_(r), cols_(c), coeffs_(st(r)*c,0.0) {}
void reset(int r, int c)
{ rows_=r; cols_=c; coeffs_.clear(); coeffs_.resize(st(r)*c,0.0); }
int rows() const {return rows_;}
int cols() const {return cols_;}
double const& operator()(int i, int j) const {return coeffs_[indexof(i,j)];}
double & operator()(int i, int j) {return coeffs_[indexof(i,j)];}
double const* operator[](int i) const {return &coeffs_[indexof(i,0)];}
double * operator[](int i) {return &coeffs_[indexof(i,0)];}
void swap(matrix& that)
{
std::swap(this->rows_,that.rows_);
std::swap(this->cols_,that.cols_);
this->coeffs_.swap(that.coeffs_));
}
private:
int rows_, cols_;
std::vector<double> coeffs_;
st indexof(int i, int j) const {return st(i)*cols+j;} // row major storage
};
inline void swap(matrix& a, matrix& b) {a.swap(b);}
matrix& operator+=(matrix& lhs, matrix const& rhs);
matrix operator+(matrix const& lhs, matrix const& rhs);
matrix operator*(matrix const& lhs, matrix const& rhs);
inline matrix& operator*=(matrix& lhs, matrix const& rhs)
{ matrix tmp = lhs * rhs; swap(tmp,lhs); return lhs; }
...
#endif
This way you won't waste any space for small matrices, and you can support large matrices. Also, the use of std::vector instead of a pointer member which points to dynamically allocated memory removes the need to define your own copy constructor, assignment operator and destructor.
Of course, you could use boost::multi_array as a matrix replacement but using a custom matrix class allows you to declare overloaded operators in your own namespace which is desirable due to ADL (argument dependent lookup).
You might think that this doesn't really answer your question. In that case, let me stress that I think you don't fully understand how arrays and pointers work / behave. This is something you should look up in a decent C++ book. One could write many pages about this topic. You can't expect to see a short answer explaining all the quirks.
Check out the Definite C++ Book Guide thread.
You need to specify all but the first dimension, e.g.
void Matrx::readMatrx(double a[][50])
From this you should be able to see that you have a fundamental problem with the way you have implemented your class, but at least you should now be able to get the code to compile.
You can to specify all dimensions or only last dimension to pass an array:
void Matrx::readMatrx(double a[][50])
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=a[i][j];
}
}
Thanks to all of you people...you were really helping...I have found myself a new definition of the class and the function definition for the matrix that fitted my need. I need you r comment on it...Below is the example of the class declaration..
#include<iostream>
#include"stdafx.h"
using namespace std;
const int M=100; const int N=100;
class Matrix
{
double A[M][N];
int m,n;
public:
Matrix(void);
Matrix(int a, int b)
{
m=a;
n=b;
for(int i=0;i<m;i++)
{
for(int j=0;j<m;j++)
A[i][j]=0.0;
}
}
Matrix operator +(Matrix b);
Matrix operator -(Matrix b);
Matrix operator *(Matrix b);
void TransPose(Matrix b);
CString printMatrix();
void readMatrix(double*);
};
and then the function implementation
#include "stdafx.h"
#include "Matrix.h"
Matrix::Matrix(void)
{
}
Matrix Matrix::operator *(Matrix b)
{
Matrix c(m,m);
if(n!=b.m)
{
HWND hndOwner(0);
MessageBoxW(hndOwner,L"Multiplication not possible row and column does not match",L"Error",NULL);
Matrix errMat(1,0);
double er[1][1]={0}; errMat.readMatrix((double *)er);
return errMat;
}
for(int i=0;i< m;i++)
{
for(int k=0;k< m;k++)
{
c.A[i][k]=0;
for(int j=0;j< n;j++)
{
c.A[i][k] = c.A[i][k]+(A[i][j] * b.A[j][k]) ;
}
}
}
return c;
}
Matrix Matrix::operator +(Matrix b)
{
Matrix c(m,n);
if((n!=b.n)||(m!=b.m))
{
HWND hndOwner(0);
MessageBoxW(hndOwner,L"Addition not possible row and column does not match",L"Error",NULL);
Matrix errMat(1,0);
double er[1][1]={0}; errMat.readMatrix((double *)er);
return errMat;
}
for(int i=0;i<m;i++)
{
for(int j=0;j< n;j++)
{
c.A[i][j]=0.0;
}
}
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
{
c.A[i][j]=A[i][j]+b.A[i][j];
}
}
return c;
}
CString Matrix::printMatrix()
{
CString strB(" "),strDisp;
for(int iRow=0;iRow<m;iRow++)
{
for(int iColumn=0;iColumn<n;iColumn++)
{
strB.Format(L"%lf ",A[iRow][iColumn]);
strDisp+=strB;
}
strDisp+="\r\n";
}
return strDisp;
}
void Matrix::readMatrix(double *ptrarr)
{
for(int i=0;i< m;i++)
{
for(int j=0;j< n;j++)
A[i][j]=*(ptrarr+i*n+j);
}
}
void Matrix::TransPose(Matrix b)
{
for(int i=0;i<b.n;i++)
{
for(int j=0;j<b.m;j++)
A[i][j]=b.A[j][i];
}
}
The simple codes in the above are working well till now...if you have any suggestion for the improvement please suggest..
You're lucky, then because:
for(int j=0;j<m;j++)
A[i][j]=0.0;
should probably be:
for(int j=0;j<**n**;j++)
A[i][j]=0.0;
Related
I created class Matrix and overloaded operator* for matrix multiplication. Inside the operator the calculations are correct but the returned result is different than this.
I tried changing this function from a friend function to a method but I got the same result.
Moreover I overloaded operators like +, - and they work fine
#include <iostream>
#include <math.h>
template<typename T> class Matrix;
template<typename T> Matrix<T> operator * (const Matrix<T>&, const Matrix<T>&);
template <typename T> class Matrix
{
public:
T *arr = nullptr;
int r, c;
friend Matrix<T> operator * <> (const Matrix<T>&, const Matrix<T>&);
Matrix(T *a, int r, int c) //parametrized constructor
{
this->arr = a;
this->r = r;
this->c = c;
}
void Print()
{
for(int i=0; i<r; i++)
{
std::cout<<"|";
for(int j=0; j<c; j++)
{
std::cout<<*(this->arr+i*c+j)<<" ";
}
std::cout<<'\b';
std::cout<<"|";
std::cout<<std::endl;
}
std::cout<<std::endl;
}
};
template <typename T> Matrix<T> operator * (const Matrix<T> &M1, const Matrix<T> &M2)
{
int r = M2.r;
int c = M1.c;
int l = M1.r;
T arr[r*c];
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
arr[i*r+j]=0;
for(int k=0; k<l; k++)
{
arr[i*r+j]+=(M1.arr[k*r+j]*M2.arr[i*l+k]);
}
std::cout<<std::endl;
}
}
//Matrix<T> x(arr, r, c);
//x.Print(); -this returns correct matrix
return Matrix<T>(arr, r, c);
}
Main
int main()
{
//here I created matrixes a and b but skipped this part of code
Matrix<int> c = a*b;
c.Print(); // - this returns wrong matrix
}
As you can see, c and x are matrices created from the same data, but I'm getting two different results.
|22 28|
|49 64|
from x.Print(), and
|4761920 4557403|
|4199040 7011960|
from c.Print().
The issue is that the Matrix constructor retains a pointer to an object that's allocated on the stack (arr). Once arr goes out of scope, any attempt to dereference the pointer will result in undefined behaviour.
You need to find a different way to manage the lifetime of the matrix data (for example, by having the matrix class keep its own copy of it).
Thanks for answers, it let me (at least partially) understand this situation.
Changing T *arr to std::vector<T> arr solved the problem.
ok so im not sure if its related to functors but from what i understood it is so
the question is:
lets assume i have the next class:
class Matrix{
public:
Matrix(int, int); // constructor
Matrix(const Matrix&); // copy constructor
Matrix& operator+= (const Matrix&);
Matrix& operator-= (const Matrix&);
int* operator[] (int) const;
private:
int rows;
int cols;
int** Mat_p;
};
and i want to overload the += and -= operators in Matrix class.
now, in order to sum or subtract 2 matrices we need to iterate over each value of both matrices and add or subtract so it will be some thing like:
Matrix& Matrix::operator+= (const Matrix& M){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] += M[indexR][indexC];
}
Matrix& Matrix::operator-= (const Matrix& M){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] -= M[indexR][indexC];
}
as you can see both operators "+=" and "-=" has the same structure give or take, so one of the basic so called "rules" is to avoid code duplication.
so the asked question is how do we avoid this duplication and keep the code effective ?
You could implement a single templated function and make two calls into it.
template<typename T>
Matrix& add_or_sub (const Matrix& M, const T &op){
for (int indexR = 0; indexR < rows; ++indexR)
for (int indexC = 0; indexC < cols; ++indexC)
Mat_p[indexR][indexC] = op(Mat_p[indexR][indexC], M[indexR][indexC]);
return *this;
}
Matrix& Matrix::operator+= (const Matrix& M){
return add_or_sub(M, std::plus());
}
Matrix& Matrix::operator-= (const Matrix& M){
return add_or_sub(M, std::minus());
}
I'm a bit late, but I guess the example is more complete. I would suggest writing a piecewise functor applicator which uses underlying scalar as operands, and returns the same type as well, and implement operators using this.
An example:
#include <iostream>
#include <functional>
using namespace std;
template <int Rows, int Cols, typename Scalar = int>
class Matrix {
public:
void piecewise_apply(const Matrix& other, std::function<Scalar(Scalar,Scalar)> f) {
for (int indexR = 0; indexR < Rows; ++indexR)
for (int indexC = 0; indexC < Cols; ++indexC)
data[indexR][indexC] = f(data[indexR][indexC], other.data[indexR][indexC]);
}
Matrix<Rows,Cols,Scalar>& operator+=(const Matrix<Rows,Cols,Scalar>& rhs) {
piecewise_apply(rhs, std::plus<Scalar>());
return *this;
}
Matrix<Rows,Cols,Scalar>& operator-=(const Matrix<Rows,Cols,Scalar>& rhs) {
piecewise_apply(rhs, std::minus<Scalar>());
return *this;
}
private:
Scalar data[Rows][Cols];
};
int main() {
Matrix<5,5> a;
Matrix<5,5> b;
a.piecewise_apply(b, [](int a, int b){return a*b;});
a -= b;
return 0;
}
The example is not complete, as it lacks initialization. Also there is no protection when &rhs == this (a interesting place for optimizations), and probably some more, but it shows the idea. As for code efficiency.. well you should rely on the compiler on this one.
One advantage of this approach is that, even if it's a bit slower in the default version, you can try writing piecewise_apply which uses more elaborate optimization techniques, like blocking, or parallelization, etc. and get speedups in various places.
For a simple version, like in your example, the copy-paste version is shorter, and easier to understand, so probably a better choice.
I have an object Matrix and I overloaded the unary minus operator and I can't manage to make my program work. If I put the return type as reference it does not allow me to return the object I created inside the function, if I put the return type as Matrix then I get segmentation fault.
in the H file :
Matrix operator - () const;
in the cpp file:
Matrix Matrix::operator - () const
{
if (isValid==false)//just a validity check
return *this;
Matrix mat(*this);//copy ctor
for (int i=0;i<row;i++)
for (int j=0;j<col;j++)
mat.matrix[i][j]=-matrix[i][j];
return mat;
}
I tried many permutations of that (adding const, adding by reference) and nothing seems to work. How do I fix this ?
What follows works without any segmentation faults. You should minimize your code by removing anything unneccessary, then gradually transform it to the code below, and see at what stage your segmentation fault vanishes.
#include <iostream>
#include <vector>
using namespace std;
class Matrix {
public:
Matrix() : isValid(true), row(0), col(0) {}
Matrix(int r, int c, int val);
Matrix(const Matrix&);
Matrix operator - () const;
private:
bool isValid;
int row, col;
vector<vector<int> > matrix;
};
Matrix::Matrix(int r, int c, int val) : isValid(true), row(r), col(c) {
matrix.resize(r);
for (int i=0; i<r; i++)
matrix[i].resize(c, val);
}
Matrix::Matrix(const Matrix& m) : isValid(true), row(m.row), col(m.col), matrix(m.matrix) {}
Matrix Matrix::operator - () const
{
if (isValid==false)//just a validity check
return *this;
Matrix mat(*this);//copy ctor
for (int i=0;i<row;i++)
for (int j=0;j<col;j++)
mat.matrix[i][j]=-matrix[i][j];
return mat;
}
main() {
int r=10, c=5;
Matrix m(r, c, 1);
Matrix m1;
m1 = -m;
}
First I have Matrix template Matrix< typename T, int Roz> and specialization of this template Matrix. But the specialization is create with constructor where argument is a size of matrix. So in example code A and Z have the same dimension. So I want to make add operator work with it. But complier say: error: no match for 'operator+' in 'Z + A'. So how I need to write operator+ for Matrix wich will be work with Matrix?
Code of Matrix templates below:
template<typename T,int Roz>
class Matrix
{
public:
T tab[Roz][Roz];
int z=Roz;
Matrix()
{
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tab[i][j]=0;
}
T& operator()(int x,int y){
return tab[x-1][y-1];
}
//Problematic operator
Matrix& operator+(Matrix<T,Roz> b)
{
Matrix<T,Roz> tmp;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
friend ostream& operator<<(ostream& out, Matrix<T,Roz> &v)
{
for(int i=0;i<v.z;++i)
{
for(int j=0;j<v.z;++j)
out<<v.tab[i][j]<<" ";
out<<endl;
}
return out;
}
};
//Specialization template
template<class T>
class Matrix<T,0>
{
private:
Matrix()
{
}
public:
vector<vector<T> > tab;
int z=0;
Matrix(int z)
{
for(int i=0;i<z;++i)
tab.push_back(vector<T>(z));
this->z = z;
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tab[i][j]=0;
}
T& operator()(int x,int y){
return tab[x-1][y-1];
}
//Problematic operator
Matrix& operator+(Matrix<T,0> b)
{
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
//Problematic operator
Matrix& operator+(Matrix<T,0> &b)
{
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
friend ostream& operator<<(ostream& out, Matrix<T,0> &v)
{
for(int i=0;i<v.z;++i)
{
for(int j=0;j<v.z;++j)
out<<v.tab[i][j]<<" ";
out<<endl;
}
return out;
}
};
When I try add for example Matrix < int,3 > and Matrix < int, 0 > this make error. How I must definie operator+ in both templates they will work together?May I have to overload operator+ in specialization template?
The code below makes error when I try add A + Z.
int main()
{
Matrix<int,3> A, B;
Matrix<int, 4> C;
Matrix<int, 0> Z(3);
A(1,1)=1;
B(1,1)=2;
Z(1,1)=1;
Z + A;//<------- here error between diffrent instance of Matrix template
}
I don't really know why you wish to add up matrices of different dimensions, but in order to do it, you must turn the method into a method template on the dimension of the matrix argument:
#include <type_traits>
template <int Roz2>
Matrix& operator+(Matrix<T,Roz2> b)
{
// check matrix argument size compatibility
std::static_assert(Roz2 >= Roz, "incompatible matrices for operator+()");
Matrix<T,Roz> tmp;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
Since Matrix<T,0> is a specialization to handle dynamic dimension, you must specialize the operator for it:
// in the generic template
Matrix& operator+(Matrix<T,0> b)
{
assert (b.z < Roz, "incompatible dynamic matrix for operator+");
Matrix<T,0> tmp(b.Roz);;
for(int i=0;i<Roz;++i)
for(int j=0;j<Roz;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
and in Matrix<T,0>:
template <int Roz>
Matrix& operator+(Matrix<T,Roz> b)
{
assert(Roz >= z,"....");
Matrix<T,0> tmp(b.z);
for(int i=0;i<z;++i)
for(int j=0;j<z;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
In the above solution, however, the operator is not commutative. In order to make it so, we need to do some change:
// define a min operator as constexpr in case the existing one is not
template<typename T> constexpr
T const& rmin(T const& a, T const& b) {
return a > b ? b : a;
}
// generic operator
template <int Roz2>
Matrix<T,rmin(Roz,Roz2)>& operator+(Matrix<T,Roz2> b)
{
constexpr int R = min(Roz,Roz2);
Matrix<T,R> tmp;
for(int i=0;i<R;;++i)
for(int j=0;j<R;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
// specialized operator on Roz=0 argument
Matrix<T,0>& operator+(Matrix<T,0> b)
{
const int r = min(z,b.z);
Matrix<T,0> tmp(r);
for(int i=0;i<r;;++i)
for(int j=0;j<r;++j)
tmp.tab[i][j]=this->tab[i][j]+b.tab[i][j];
}
// specialized operator in Roz=0 template
Matrix& operator+(Matrix<T,Roz> b)
{
return b + *this;
}
You will have to duplicate the code for const & parameters taking operators (or perhaps simply get rid of the non const parameter versions which don't seem very useful in that context).
Note the use of a static assert to limit the use of the operator with matrices of equal or larger dimension (this is a C++11 feature) in the non commutative version of the operators.
See this question on the topic of min not being a constexpr function template for further details.
I'm very much still a beginner at programming but I have come across the error "lvalue required as left operand of assignment" and I am unsure about how to resolve this issue after looking through various other discussions. The error appears in a class I made for Matrices when I overloaded certain operators. Here is part of the code,
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
#include "MVector.h"
class Matrix {
private:
vector<double> columns;
vector<vector<double> > A;
public:
//constructor
explicit Matrix(){};
explicit Matrix(int n,int m):columns(m),A(n,columns){};
explicit Matrix(int n,int m,double x):columns(m,x),A(n,columns){};
//destructor
~Matrix(){};
//equate matrices
Matrix &operator=(const Matrix &rhs) {A=rhs.A;return *this;};
//set all values to a double
Matrix &operator=(double x)
{
int rows=this->rows();
int cols=this->cols();
for (int i=0;i<rows;i++)
{
for (int j=0;j<cols;j++)
{
A[i][j]=x;
}
}
}
//access data in matrix (const)
double operator()(int i,int j) const {return A[i][j];};
//access data in matrix
double operator()(int i,int j) {return A[i][j];};
//returns the number of rows
int rows() const {return A.size();};
//returns the number of cols
int cols() const {return columns.size();};
//check if square matrix or not
bool check_if_square() const
{
if (rows()==cols()) return true;
else return false;
}
};
and this is one of the overloaded operators which produces the error
const Matrix operator+(const Matrix &A,const Matrix &B)
{
//addition of matrices
//check dimensions
if (!(A.cols()==B.cols()) || !(A.rows()==B.rows()))
{
cout << "Error: Dimensions are different \n Ref: Addition of Matrices";
throw;
}
else
{
int dim_rows = A.rows();
int dim_cols = B.cols();
Matrix temp_matrix(dim_rows,dim_cols);
for (int i=0;i<dim_rows;i++)
{
for (int j=0;j<dim_cols;j++)
{
temp_matrix(i,j)=A(i,j) + B(i,j);
}
}
return temp_matrix;
}
}
I assume I've done something wrong, if anyone can help and explain what I'm doing wrong that would be really appreciated. Thanks for the help!
It means that you cannot assign to the result of an rvalue-expression, in this case the temporary returned by operator()(int,int). You probably want to change your non-const operator()(int,int) in the Matrix class to be:
double& operator()( int x, int y ) { return A[i][j]; }
Additionally (and unrelated to the question) you might want to simplify your matrix class and store only the dimensions and a single one dimensional vector to store all the elements. Then the accessors would perform some basic arithmetic (something like row*columns()+column) to get to the actual value in the one dimensional vector.