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
}
Related
I'm trying to make a Matrix struct which would work with various data types, including my Complex struct:
struct Complex {
double re = 0, im = 0;
Complex operator*(const Complex& other) const {
return Complex(re * other.re - im * other.im, im * other.re + re * other.im);
}
Complex operator*(const double& other) const {
return Complex(re * other, im * other);
}
Complex() {}
Complex(double a) : re(a) {}
Complex(double a, double b) : re(a), im(b) {}
};
std::ostream& operator<<(std::ostream& out, Complex z) {
out << z.re << " " << z.im << "i";
return out;
}
template <typename T>
Complex operator*(const T& c, const Complex& z) {
return z * c;
}
The obvious way is to make a template like one in the code below:
template <typename T>
struct Matrix {
std::vector<T> m;
unsigned int rows, cols;
Matrix<Complex> operator*(const Complex& z) const {
Matrix<Complex> result(rows, cols);
for (int i = 0; i < m.size(); i++) {
result.m[i] = m[i] * z;
}
return result;
}
void operator*=(const Complex& z) {
(*this) = (*this) * z; // <- ideally we're trying to get this to work
}
void operator=(const Matrix<T>& other) {
rows = other.rows;
cols = other.cols;
m.resize(rows * cols);
m = other.m;
}
Matrix(const unsigned int& rows, const unsigned int& cols) : rows(rows), cols(cols) {
m.resize(rows * cols);
}
Matrix(const Matrix<T>& other) : rows(other.rows), cols(other.cols) {
(*this) = other;
}
};
int main() {
Complex z(1, 1);
Matrix<double> A(1, 1);
A.m[0] = 2.0;
std::cout << (A * z).m[0] << std::endl; // works as it should because a temporary Matrix<Complex> gets created
A *= z; // and here we're introducing the problem
std::cout << A.m[0] << std::endl;
}
The problem arises when calling *= operator. We're trying to call an unexisting = operator overload. My first attempt was to write something like this instead:
template <typename T_other>
void operator=(const Matrix<T_other>& other) {
rows = other.rows;
cols = other.cols;
m.resize(rows * cols);
for (int i = 0; i < m.size(); i++) {
m[i] = other.m[i];
}
}
This however leads to other problems:
The type of A is still Matrix<double> and after the multiplication it should be Matrix<Complex> to store complex numbers.
There is no conversion from Complex to double as it results in loss of data (the imaginary part).
Also, I would like to avoid creating a template specialization for Matrix<Complex>, but if there's no other way I'll accept it.
C++ is statically typed. Once you declare a variable and type, you can't change the type of that variable.
template <typename T>
struct Matrix {
void operator*=(const Complex& z) {
(*this) = (*this) * z;
}
}
The *= operator overload for your Matrix doesn't make sense. A Complex can hold the value of a double with imaginary part 0, but a double can never hold the value of a Complex.
Multiplying a real matrix by a complex number necessarily produces a complex matrix. So you try and assign the complex RHS to the real LHS - and either that makes no sense and shouldn't be done, or you have some idea for how to convert that (e.g. keep real part, keep absolute value etc) and then have to implement a Matrix<double> constructor from Matrix<Complex>.
Real numbers are a subset of complex numbers, so just make A a Matrix<Complex> from the beginning if you ever want to make it complex later.
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.
I am trying to build a SquareMatrix template class by using a constructor that accepts 4 parameters as the 4 submatrices a, b, c, d occupying the four quadrants (a = northwest, b = northeast, c = southwest, d = southeast) of the matrix. Shown below:
template<class T> class SquareMatrix {
public:
SquareMatrix(){}
SquareMatrix(const T first, const T second, const T third, const T fourth) {
a = first;
b = second;
c = third;
d = fourth;
}
SquareMatrix<T>(const SquareMatrix<T>& rhs) { // copy constructor
a = rhs.getA();
b = rhs.getB();
c = rhs.getC();
d = rhs.getD();
}
SquareMatrix& operator=(const SquareMatrix rhs) { // assignment operator
if (&rhs != this) {
SquareMatrix(rhs);
}
return *this;
}
~SquareMatrix() {} // destructor
// getters and setters
T getA() const {return a;}
T getB() const {return b;}
T getC() const {return c;}
T getD() const {return d;}
void setA(const T& input) {a = input;}
void setB(const T& input) {b = input;}
void setC(const T& input) {c = input;}
void setD(const T& input) {d = input;}
private:
// 4 quadrants
// [a, b;
// c, d]
T a, b, c, d;
};
template<class T> SquareMatrix<T> operator+(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() + rhs.getA() );
ret.setB( ret.getB() + rhs.getB() );
ret.setC( ret.getC() + rhs.getC() );
ret.setD( ret.getD() + rhs.getD() );
return ret;
};
template<class T> SquareMatrix<T> operator-(const SquareMatrix<T> lhs,
const SquareMatrix<T>& rhs) {
SquareMatrix<T> ret(lhs);
ret.setA( ret.getA() - rhs.getA() );
ret.setB( ret.getB() - rhs.getB() );
ret.setC( ret.getC() - rhs.getC() );
ret.setD( ret.getD() - rhs.getD() );
return ret;
};
// this is the implementation of Strassen's algorithm
template<class T> SquareMatrix<T> operator*(const SquareMatrix<T>& lhs,
const SquareMatrix<T>& rhs) {
T product_1 = lhs.getA() * ( rhs.getB() - rhs.getD() );
T product_2 = ( lhs.getA() + lhs.getB() ) * rhs.getD();
T product_3 = ( lhs.getC() + lhs.getD() ) * rhs.getA();
T product_4 = lhs.getD() * ( rhs.getC() - rhs.getA() );
T product_5 = ( lhs.getA() + lhs.getD() ) * ( rhs.getA() + rhs.getD() );
T product_6 = ( lhs.getB() - lhs.getD() ) * ( rhs.getC() + rhs.getD() );
T product_7 = ( lhs.getA() - lhs.getC() ) * ( rhs.getA() + rhs.getB() );
SquareMatrix<T> ret;
ret.setA(product_5 + product_4 - product_2 + product_6);
ret.setB(product_1 + product_2);
ret.setC(product_3 + product_4);
ret.setD(product_1 + product_5 - product_3 - product_7);
return ret;
};
Now, I am trying to create a nested 4x4 matrix, by doing:
int main() {
cout << "Example: a 4x4 matrix: " << endl;
// 4 single quadrants
SquareMatrix<int> M_1A(1, 2, 3, 4);
SquareMatrix<int> M_1B(5, 6, 7, 8);
SquareMatrix<int> M_1C(9, 10, 11, 12);
SquareMatrix<int> M_1D(13, 14, 15, 16);
// 4x4 matrix M_1
SquareMatrix< SquareMatrix<int> > M_1(M_1A, M_1B, M_1C, M_1D);
// test
cout << "test: " << endl;
cout << M_1.getA().getA() << endl;
return 0;
}
The intended matrix output should be M_1 = [1,2,5,6; 3,4,7,8; 9,10,13,14; 11,12,15,16].
I use the M_1.getA().getA() command to first access M_1A and then access 1 nested inside it, but instead the output display a big number that constantly changes, perhaps an address? (last time I tried it yielded 6684672).
Is there a way to implement a matrix class in this manner?
(EDIT: now included assignment operator and destructor, likely sources of the bug)
As the comments suggested, it is the assignment operator that is faulty.
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix(rhs); // <-- This creates a temporary that
// dies off after that line is executed
}
return *this;
}
The assignment operator doesn't do any assignment. Instead a temporary SquareMatrix is made.
To fix this problem, either
1) Not supply any assignment operator, copy constructor, or destructor, since the type T should be safely copyable.
2) Fix the assignment operator so that it works correctly:
#include <algorithm>
//...
SquareMatrix& operator=(const SquareMatrix rhs) {
if (&rhs != this) {
SquareMatrix t(rhs);
std::swap(t.a, a);
std::swap(t.b, b);
std::swap(t.c, c);
std::swap(t.d, d);
}
return *this;
}
The assignment now works. However I suggest not writing code that need not be written, and your buggy implementation is the case in point.
In your case, if you let the compiler generate the assignment operator and/or rely on T in the template to have correct copy semantics, your class would have worked correctly.
Paul's comments are right on the mark. Although your SquareMatrix is not built-in, it is declared to be consisting of 4 elements of type T. The default copy c'tor for your class will be using the assignment operator or assignment c'tor of the actual type that T is representing in your usage.
I have some suggestions to improve the code:
If T is of a type that has a memory footprint that is bigger than a pointer/int: it is more efficient to let your c'tor receive the elements bij const reference like so:
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
Use copy constructors as much as possible: that way the four elements don't get initialized first and then assigned later. Instead, they get initialized with the correct values at once.
SquareMatrix( const T& _a, const T& _b, const T& _c, const T& _d)
: a( _a), b( _b), c( _c), d( _d)
{ /* empty body */ }
Choose your names wisely to simplify things. Don't introduce extra mappings in name schemes when you don't have to; it just creates opportunities to slip. I already applied that in point 1 above :-).
Don't 'program by wishful thinking': writing in comments or type/variable names that something is supposed to be something will not make it that. In your case: your class IS NOT a square matrix, nor even a matrix. To the compiler it is a data type consisting of four elements, named a, b, c and d, respectively, of a type T to be defined at compile time.
I have two classes, my_matrix and my_vector classes, where my_vector derives from my_matrix.
When I do my_matrix tmp = vec * mat, it returns a matrix (mat is an instance of my_matrix and vec is an instance of my_vector). I am fine here.
But when I do my_vector tmp = mat * vec, I get this error in clang++:
no viable conversion from 'my_matrix' to 'my_vector'
and this error in g++:
conversion from 'my_matrix' to non-scalar type 'my_vector' requested
I think I know what the problem is. After mat and vec are multiplied, the return type is my_matrix and you can't cast base class to derived class.
What do you think the solution for this would be?
I have tried defining void operator*(my_vector&, my_matrix&) (not a member function of the derived class) which calls my_vector operator*(my_matrix&) in the derived class, but it does not work so far.
class my_matrix{
public:
my_matrix operator*(my_matrix& other_mat){
my_matrix tmp(row, other_mat.col);
// for loop to matrix multiply that fill up the tmp
return tmp;
}
};
class my_vector:public my_matrix{
public:
// not sure if I need operator* here
// Somehow I want to bring the my_vector tmp = mat * vec; here so
// it would return vector instead of matrix
// I have tried : but not successful
// my_vector operator*(my_matrix&)
// void operator*(my_vector&, my_matrix&); (non member)
};
int main(){
my_matrix mat = {{1,2,3},{4,5,6}}; // 2x3
my_vector vec = {1,2,3}; // 3x1
my_vector tmp = mat * vec; // 2x3 * 3*1 gives 2x1 vector
}
Try something like this:
class my_matrix {
public:
my_matrix operator*(const my_matrix& other_mat) const {
my_matrix tmp(row, other_mat.col);
// for loop to matrix multiply that fill up the tmp
return tmp;
}
};
class my_vector : public my_matrix {
public:
using my_matrix::operator*;
my_vector operator*(const my_vector& other_vec) const {
my_vector tmp(...);
// for loop to vector multiply that fill up the tmp
return tmp;
}
};
my_vector operator*(const my_matrix &lhs, const my_vector &rhs)
{
my_vector tmp(...);
// for loop to vector multiply that fill up the tmp
return tmp;
}
int main() {
my_matrix mat = {{1,2,3},{4,5,6}}; // 2x3
my_vector vec = {1,2,3}; // 3x1
my_vector tmp = mat * vec; // 2x3 * 3x1 gives 2x1 vector
}
For starters, the existing operator*'s parameter is wrong:
my_matrix operator*(my_matrix& other_mat){
The parameter to the * operator should be const, and the method should be const itself. After all, the multiplication operator should not be modifying either of the operands:
my_matrix operator*(const my_matrix& other_mat) const {
With that problem out of the way, you can now meaningfully overload the operator:
my_vector operator*(const my_vector& other_mat) const {
And implement the multiplication operation in whatever way you want to define this operation to work.
Now, multiplication by a my_matrix returns in a my_matrix, and multiplication by a my_vector returns a my_vector. Your my_matrix overloads the * operator, and the return value becomes dependent on what you're multiplying it by.
I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through
This is what I call to cause the problems.
cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
Kev *= 4.0f;
cMatrix Baz = Kev;
Kev = Kev+Baz; //HERE!
What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.
//header
class cMatrix
{
private:
float* _internal;
UInt32 _r;
UInt32 _c;
bool _zeroindexed;
//fast, assumes zero index, no safety checks
float cMatrix::_getelement(UInt32 r, UInt32 c)
{
return _internal[(r*this->_c)+c];
}
void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
{
_internal[(r*this->_c)+c] = Value;
}
public:
cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
cMatrix( cMatrix& m);
~cMatrix(void);
//operators
cMatrix& operator + (cMatrix m);
cMatrix& operator += (cMatrix m);
cMatrix& operator = (const cMatrix &m);
};
//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
cMatrix::~cMatrix(void)
{
delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m)
{
return cMatrix(*this) += m;
}
cMatrix& cMatrix::operator*(float f)
{
return cMatrix(*this) *= f;
}
cMatrix& cMatrix::operator*=(float f)
{
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] *= f;
}
return *this;
}
cMatrix& cMatrix::operator+=(cMatrix m)
{
if (_c != m._c || _r != m._r)
{
throw new cCTException("Cannot add two matrix classes of different sizes.");
}
if (!(_zeroindexed && m._zeroindexed))
{
throw new cCTException("Zero-Indexed mismatch.");
}
for (UInt32 row = 0; row < _r; row++)
{
for (UInt32 column = 0; column < _c; column++)
{
float Current = _getelement(row, column) + m._getelement(row, column);
_setelement(row, column, Current);
}
}
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix &m)
{
if (this != &m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
delete[] _internal;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
return *this;
}
Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:
cMatrix cMatrix::operator+(cMatrix const& m)
{
cMatrix matrix(*this);
matrix += m;
return matrix;
}
cMatrix cMatrix::operator*(float f)
{
cMatrix matrix(*this);
matrix *= m;
return matrix;
}
You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.
PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.
PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.
IMO the canonical form of overloading addition is this:
class X {
public:
X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};
inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}
The same goes for -, *, /, where applicable.
Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.