I am trying to make matrix structure with overloading operators '+' and '='.
Matrix structure:
struct Matrix{
int rows;
int cols;
std::vector<int> data;
Matrix(int rows, int cols, int val); //creates matrix row*col and fills every position with val
Matrix(const Matrix &m); //copy constructor
Matrix(int rowcol = 0); //creates matrix rowcol*rowcol filled with zeros
Matrix & operator=(const Matrix &m);
void printMatrix(); //prints the matrix
...
};
Operators:
Matrix & Matrix::operator=(const Matrix &m) //assings matrix m to the new matrix
{
}
Matrix operator+(const Matrix &a, const Matrix &b) //sums two matrices
{
//I know how to make the algorithm for summing two matrices, however i don´t know how
//to return the result into existing matrix
}
And main function:
int main(){
Matrix A(3,3,1);
Matrix B(3,3,2);
Matrix C(3,3,0);
C = A + B;
C.printMatrix();
...
return 0;
}
I don´t know how to make it work. I tried something like this for the '=' operator:
Matrix & Matrix::operator=(const Matrix &m)
{
static matrix d(m); //using copy constructor
return d;
}
but it didn´t work. It created new matrix with dimensions 0x0. Any advice on how to implement it?
A working way to implement that operator= would be as follows:
Matrix& Matrix::operator=(const Matrix &m)
{
this->rows = m.rows;
this->cols = m.cols;
this->data = m.data;
return *this;
}
I won't approach the algorithm needed for operator+, but the surrounding machinery is also surprisingly simple:
Matrix operator+(const Matrix &a, const Matrix &b) //sums two matrices
{
Matrix result(<num of rows>, <num of cols>, 0);
// do things with result here, using your algorithm, a, and b
// e.g. result.data[?] = a.data[?] ? b.data[?]
return result;
}
To make this easier, since your data is one-dimensional (good! this is efficient!), you may want to implement an accessor that takes x and y dimensions and returns an index into data. For example:
int& Matrix::val(const int x, const int y)
{
assert(x < cols);
assert(y < rows);
return data[x + y*cols];
}
The result of this may be both read and written, like this:
result.val(x1, y1) = a.val(x2, y2) + b.val(x3, y3);
Where those co-ordinates and the + are just things I made up, and should come from your algorithm.
If you also want an operator+=, to affect an existing matrix, then:
Matrix& Matrix::operator+(const Matrix &b) //sums two matrices
{
// do things with your object here, using your algorithm and b
return *this;
}
Where I return *this for the member operators, that's not strictly necessary, though it is conventional, and it allows for easy chaining of operations (if you're into that kind of thing). You can find more information on operator overloading in your book.
Related
First of all it's an exercise given to me so i can't change things and have to work with it.
I have a 2d vector aka a matrix. My header file looks like this
#include <vector>
#include <iostream>
using namespace std;
class Matrix{
private:
vector<vector<double>> 2d;
public:
explicit Matrix(unsigned int sizeY=0,unsigned int sizeX=0,double value= 0.0);
~Matrix() = default;
Matrix(const Matrix &other);
Matrix(Matrix &&other) = default;
Matrix& operator=(const Matrix &other);
Matrix& operator=(Matrix &&other) = default;
//other + - operators
//INDEX
vector<double>& at(unsigned int i);
const vector<double>& at(unsigned int i)const;
const vector<double>& operator[] (double m) const;
vector<double>& operator[] (double m);
};
Matrix operator+(const Matrix& d1, const Matrix& d2);
Matrix operator-(const Matrix& d1, const Matrix& d2);
ostream& operator<<(ostream &o, const Matrix& v);
istream& operator>>(istream &i, Matrix& v);
So now I implemented everything except the << and >> operator.
Now the question if i want to go through the 2d vec matrix is there another way to get the "depth"
outside the Matrix class except writing a getter ?
If the Matrix is N X M e.g. 4x4 i can get the 2nd 4 the "width" with something like 2d[0].size() but i cant figure out how I can get the "depth" otherwise then use a getter.
Also i cant change 2d to public or use templates.
I tried for around 2-3 hours myself and couldnt find any solution and maybe its not possible under the given conditions.
2d[0].size() is giving you the length of the first vector stored in 2d. To get the length of 2d you can just call the same directly on 2d.
2d.size() = length of 2d
2d[0].size() = length of first vector stored in 2d
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'm having some trouble implementing an assignment operator for a matrix class. It seems that the compiler doesn't want to recognize my overloaded assignment operator (I think?) and I'm not sure why. I know there are some internet articles on the various issues with implementing matrix classes in c++ (which have helped me get this far) but this time I can't seem to parallel my current predicament with any other help already out there. Anyway, I would greatly appreciate it if someone could help explain what I'm doing wrong. Thanks!
Here are my error messages:
In file included from Matrix.cpp:10:
./Matrix.h:20:25: error: no function named 'operator=' with type 'Matrix &(const Matrix &)'
was found in the specified scope
friend Matrix& Matrix::operator=(const Matrix& m);
^
Matrix.cpp:79:17: error: definition of implicitly declared copy assignment operator
Matrix& Matrix::operator=(const Matrix& m){ //m1 = m2
^
Matrix.cpp:89:13: error: expression is not assignable
&p[x][y] = m.Element(x,y);
~~~~~~~~ ^
3 errors generated.
Here is my assignment operator code in my .cpp file:
Matrix& Matrix::operator=(const Matrix& m){ //m1 = m2
if (&m == this){
return *this;
}
else if((Matrix::GetSizeX() != m.GetSizeX()) || (Matrix::GetSizeY()) != m.GetSizeY()){
throw "Assignment Error: Matrices must have the same dimensions.";
}
for (int x = 0; x < m.GetSizeX(); x++)
{
for (int y = 0; y < m.GetSizeY(); y++){
&p[x][y] = m.Element(x,y);
}
}
return *this;
here is my matrix header file:
class Matrix
{
public:
Matrix(int sizeX, int sizeY);
Matrix(const Matrix &m);
~Matrix();
int GetSizeX() const { return dx; }
int GetSizeY() const { return dy; }
long &Element(int x, int y) const ; // return reference to an element
void Print() const;
friend std::ostream &operator<<(std::ostream &out, Matrix m);
friend Matrix& Matrix::operator=(const Matrix& m);
long operator()(int i, int j);
friend Matrix operator*(const int factor, Matrix m); //factor*matrix
friend Matrix operator*(Matrix m, const int factor); //matrix*factor
friend Matrix operator*(Matrix m1, Matrix m2); //matrix*matrix
friend Matrix operator+(Matrix m1, Matrix m2);
Your assignment operator should be a member function, not a friend. Your other operators should take parameters as const Matrix &, otherwise you'll make a copy of the Matrix objects used by the operator.
You're taking the address of the element:
&p[x][y] = m.Element(x,y);
when you want to assign to it, like this:
p[x][y] = m.Element(x,y);
friend Matrix& Matrix::operator=(const Matrix& m);
This above part makes little sense since operator= must be defined as a member function within the class.
Actually I think your life would be a lot easier if you avoided the need for friends here (or at least so many of them). A self-sufficient public interface for a matrix should allow you to implement all the desired operators, whether or not they're members of the class.
Perhaps the first thing you should seek is that self-sufficient public interface so that you don't actually need something like a matrix multiplication operator to be a friend, since otherwise the likely temptation would be to make every operation involving matrices require access to the matrix internals.
I've written a C++ interface to LAPACK, but I'm running into some memory issues that have made me reconsider some of operator overloading.
Right now, I have overloaded the operator* outside of the the class definition (but as a friend to the Matrix class) that takes two Matrix objects, allocates a third with the proper dimensions, uses D(GE/SY)MM to compute the product (storing into the internal storage of the newly allocated matrix) and then returns the pointer to that new matrix. I.E.
class Matrix {
...
friend Matrix* operator*(const Matrix&, const Matrix&);
...
}
Matrix* operator*(const Matrix& m1, const Matrix& m2) {
Matrix *prod = new Matrix(m1.rows_, m2.cols_);
if(m1.cols_!=m2.rows_) {
throw 3008;
} else {
double alpha = 1.0;
double beta = 0.0;
if(m1.symm_=='G' && m2.symm_=='G'){
dgemm_(&m1.trans_,&m2.trans_,&m1.rows_,&m2.cols_,&m1.cols_,&alpha,m1.data_,
&m1.rows_,m2.data_,&m1.cols_,&beta,prod->data_,&m2.cols_);
} else if(m1.symm_=='S'){
char SIDE = 'L';
char UPLO = 'L';
dsymm_(&SIDE,&UPLO,&m1.rows_,&m2.cols_,&alpha,m1.data_,&m1.rows_,m2.data_,
&m2.cols_,&beta,prod->data_,&m2.cols_);
} else if(m2.symm_=='S'){
char SIDE = 'R';
char UPLO = 'L';
dsymm_(&SIDE,&UPLO,&m2.rows_,&m1.cols_,&alpha,m2.data_,&m2.rows_,m1.data_,
&m1.cols_,&beta,prod->data_,&m1.cols_);
};
}
return prod;
};
Then I utilize
Matrix *A, *B, *C;
// def of A and B
C = (*A)*(*B);
And this works just fine. The problem I'm having is that I have to allocate a new matrix every time I do this. What I'd like to be able to do is allocate the C matrix once and place the product of A and B into the internal storage of C (C->data_). From what I've been able to find on operator overloading, I can't find a nice way to do this. I'm aware I can use a member function to do this, (i.e. C->mult(A,B)) but I'd like to avoid that if at all possible (I'm coding this for ease of development for non-CSE types). Any ideas would be greatly appreciated.
class Matrix
{
struct Product
{
const Matrix* a;
const Matrix* b;
};
Matrix& operator = (const Product& p)
{
// if this matrix dims differ from required by product of p.a and p.b
// reallocate it first and set dims
// {
// rows = ....; cols = ....;
// delete [] data;
// data = new [rows*cols];
// }
// then calculate product
// data[0] = ...;
// ...
return *this;
}
Product operator * (const Matrix& op) const
{
Product p;
p.a = this;
p.b = &op;
return p;
}
int rows,cols;
double* data;
/// your Matrix stuff
// ...
};
void test()
{
Matrix a(4,2),b(2,4),c;
c = a * b; // (note a*b returns Product without calculating its result
// result is calculated inside = operator
c = a * b; // note that this time c is initialized to correct size so no
// additional reallocations will occur
}
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.