I am implementing this class from https://isocpp.org/wiki/faq/operator-overloading
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double& operator() (unsigned row, unsigned col); // Subscript operators often come in pairs
double operator() (unsigned row, unsigned col) const; // Subscript operators often come in pairs
// ...
~Matrix(); // Destructor
Matrix(const Matrix& m); // Copy constructor
Matrix& operator= (const Matrix& m); // Assignment operator
// ...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//, data_ ← initialized below after the if...throw statement
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= rows_ || col >= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= rows_ || col >= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
In my main program I am declaring
Matrix *m = new Matrix(20,20)
Now how to access the elements ?
Normally
Matrix m(20,20)
will do the job.
But how to access in the other case ?
I tried
*m(i,j) - didn't work
m->operator()(i,j) - didn't work
(*m)(i,j) should do the trick. But then you might as well implement an equivalent at method so you can write m->at(i,j).
Related
I am trying to design a basic matrix class having data allocated in device. I am having some problems when inserting an element into the matrix given its row and col. This is my actual code:
template <typename CellType_>
class CUDAMatrix {
public:
using CellType = CellType_;
CUDAMatrix(size_t rows_, size_t cols_) {
_rows = 0;
_cols = 0;
resize(rows_, cols_);
}
~CUDAMatrix() {
cudaFree(_data);
}
inline size_t rows() const {
return _rows;
}
inline size_t cols() const {
return _cols;
}
inline void _init() {
_capacity = _rows * _cols;
CUDA_CHECK(cudaMalloc((void**) &_data, sizeof(CellType) * _capacity));
}
inline void resize(size_t rows_, size_t cols_) {
// if size is ok, do nothing
if (_rows == rows_ && _cols == cols_)
return;
_rows = rows_;
_cols = cols_;
if (rows_ * cols_ <= _capacity)
return;
cudaFree(_data);
_init();
}
inline void set(const size_t row, const size_t col, const CellType& val) {
if (row > _rows || col > _cols) {
throw std::out_of_range("[Matrix::at] index out of range");
}
CUDA_CHECK(cudaMemcpy(_data[row * _cols + col], &val, sizeof(CellType), cudaMemcpyHostToDevice));
}
inline void clear() {
cudaFree(_data);
_capacity = 0;
_cols = 0;
_rows = 0;
}
protected:
size_t _cols;
size_t _rows;
size_t _capacity;
CellType* _data;
};
int main() {
const size_t rows = 620;
const size_t cols = 480;
using MyMat = CUDAMatrix<float>;
MyMat mymat(rows, cols);
for (size_t r = 0; r < mymat.rows(); ++r) {
for (size_t c = 0; r < mymat.cols(); ++c) {
mymat.set(r, c, 1.f);
}
}
}
How I can take an element from host and copy it to device? I am getting the error argument of type "float" is incompatible with parameter of type "const void *". The error arise here when I call cudaMalloc.
cudaMemcpy(_data[row * _cols + col], val, sizeof(CellType), cudaMemcpyHostToDevice)
While almost all possible memcpy require pointers for sources and targets, you are attempting to pass cell and val values. You should pass the pointer to cell and &val.
cudaMemcpy(&_data[row * _cols + col], &val, sizeof(CellType), cudaMemcpyHostToDevice)
cudaMemcpy requires pointer as src and dst, _data[index] does not return a pointer. The right way should be:
cudaMemcpy(&_data[row * _cols + col], &val, sizeof(CellType), cudaMemcpyHostToDevice)
I've following code:
#include <iostream>
#include <cassert>
class Matrix
{
private:
double m_data[3][3]{};
public:
double& operator()(int row, int col);
};
double& Matrix::operator()(int row, int col)
{
assert(col >= 0 && col < 3);
assert(row >= 0 && row < 3);
return m_data[row][col];
}
int main()
{
Matrix matrix;
matrix(1, 2) = 4.5;
std::cout << matrix(1, 2) << '\n';
return 0;
}
I'm wondering how does following line assigns the 4.5 to m_data[1][2].
matrix(1, 2) = 4.5;
Actually, there is no assignment inside the function double& operator()(int row, int col). It has only return m_data[row][col]; statement. Shouldn't it just return value at m_data[1][2]. In that case it would be 0 by default.
This function:
double& Matrix::operator()(int row, int col)
return a reference of a double variable, not just a value.
matrix(1, 2) = 4.5;
matrix(1, 2) returns a reference of that variable, and that reference get assigned a value, that is 4.5
I am a Java developer, but now I need a C++ library and I am not so experienced in this language. In particular, I always get confused about pointers, references and memory allocation. This I think is the reason why I am getting an error at a matrix class I am developing.
The main code:
#include "stdafx.h"
#include "matrix.cpp"
void matrixtest();
int main()
{
matrixtest();
system("pause");
return 0;
}
void matrixtest()
{
// let's try 3x3 matrices
static const int arr1[] = {1, 2, 1, -1, 1, 2, 2, 3, -4};
static const int arr2[] = {0, 2, 2, 1, -1, 0, 3, 2, -2};
vector<int> values1(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0]));
vector<int> values2(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0]));
matrix A(values1, 3);
matrix B(values2, 3);
matrix sum = A + B;
sum.show();
matrix diff = A - B;
diff.show();
matrix prod = A * B;
prod.show();
}
matrix.cpp interesting code:
matrix::matrix(vector<int> v, int r) : values(v), rows(r) {
values = v;
rows = r;
}
// [...]
matrix& matrix::operator += (const matrix& rhs) {
matrix result = (*this) + rhs;
(*this) = result;
return *this;
}
matrix matrix::operator + (const matrix& rhs) {
if (rows != rhs.rows || values.size() != rhs.values.size()) {
throw std::length_error("Matrices shapes mismatch");
}
matrix result(values, rows);
for (auto& i : values) {
result.values[i] = this->values[i] + rhs.values[i];
}
return result;
}
// [...]
void matrix::show() {
string delimiter = "";
for (auto& i : values) {
delimiter = "";
for (auto j = 0; j < values.size()/rows; j++) {
cout << delimiter << values[i * values.size()/rows + j]; // this is the line giving the error
delimiter = ",";
}
std::cout << std::endl;
}
}
full matrix.hpp file:
#ifndef matrix_hpp
#define matrix_hpp
class matrix {
private:
std::vector<int> values; // size is found by values.size()
int rows; // columns is values.size()/rows
public:
matrix(vector<int>, int); // base ctor.
matrix(const matrix& rhs); // copy ctor.
matrix& operator=(const matrix& rhs); // assign. ctor.
~matrix(); // dtor.
int& operator () (int row, int column);
const int& operator () (int row, int column) const;
matrix operator + (int scalar) const;
matrix operator - (int scalar) const;
matrix operator * (int scalar) const;
matrix& operator += (int scalar);
matrix& operator -= (int scalar);
matrix& operator *= (int scalar);
matrix operator + (const matrix&);
matrix operator - (const matrix&);
matrix operator * (const matrix&);
matrix& operator += (const matrix&);
matrix& operator *= (const matrix&);
// should be private ??
void reshape(int newRows, int newColumns);
void show(); //used for dev. only
void range(int start, int defaultStep = 1);
void fill(int value);
void randint(int lowerBound, int upperBound);
};
#endif /* CMatrix_hpp */
This class is based on an example given at matrix example.
The error says '0xC0000005: Access violation reading location 0x5820A694.'
So I am guessing the memory allocation is wrong and/or there is an out of bounds array and/or I am messing with the '&' operators.
Edit: I get the following trace:
this 0x00dffe24 {values={ size=9 } rows=3 } matrix *
So, the matrix does exist, but for some reason I am getting the error.
The for loop that you are using, before the one causing the error
for (auto& i : values)
is a range-based for loop.
With this you will get the values present in vector(values).
But based on the logic you have written what you want here is an index that represents the row you are working with.
You should go for the normal for loop.
for(int i =0; i<rows; ++i)
I'm writing the Math module for an OpenGLES project.
I wrote a class for managing float matrices for a generic size
template <unsigned int N>
class MatrixN {
public:
float m[N*N];
MatrixN(){}
virtual ~MatrixN(){}
void identify();
MatrixN& operator=(const MatrixN& b);
};
template <unsigned int N>
MatrixN<N> operator*(const MatrixN<N>& a, const MatrixN<N>& b);
//CPP file implementation
template<unsigned int N>
MatrixN<N> operator*(const MatrixN<N>&a, const MatrixN<N> &b) {
MatrixN<N> matrix;
for(unsigned int i = 0; i < N; i++){
for(unsigned int j = 0; j < N; j++){
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++){
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
And the i create a sub-class for managing 3x3 matrices
class Matrix3 : public MatrixN<3> {
public:
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
Why when i perform this operation
//Rotations instances of Matrix3
Matrix3 rotation = this->rotation * input.rotation;
i get this error at compile time?
no viable conversion from 'MatrixN<3U>' to 'const Matrix3'
It's because the multiply operation return MatrixN<3> and is not Matrix3
In this case, you can create a constructor in Matrix3 that accept MatrixN<3>
code (not tested) :
class Matrix3 : public MatrixN<3> {
public:
Matrix3 (const MatrixN<3>& mat){/*set internal values*/}
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
The problem is that the result type of operator* is MatrixN<N> but the type of rotation is Matrix3 and the implicit cast does not work because this would be a downcast.
As a possible solution you can overwrite the operator* for Matrix3 inputs and outputs. With a helper function you can spare some code if you would like to reuse it. For example:
template< MatrixType >
MatrixType multiple(const MatrixType& a, const MatrixType& b, size_t N )
{
MatrixType matrix;
for(unsigned int i = 0; i < N; i++)
{
for(unsigned int j = 0; j < N; j++)
{
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++)
{
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
Matrix3 operator*(const Matrix3& a, const Matrix3& b)
{
return multiple< Matrix3 >( a, b, 3 );
}
Note that this can be a bit dangerous because there is not any protection to avoid overflow, so the "user" of the multiple function should be careful.
Your multiplication operator is implemented in terms of MatrixN<N>. Your derived type Matrix3 isn't immediately one of those but has one of those as base. So there is still a derived to base conversion to call the operator and the type returned isn't immediately the type you want.
You can define your multiplication operator to take any type as arguments and return this type and then constrain it to only really take types which are derived from MatrixN<N>:
template<typename Matrix,
typename = std::enable_if_t<std::is_base_of<MatrixN<Matrix::size>, Matrix>::value>>
Matrix operator*(const Matrix&a, const Matrix &b) {
constexpr unsigned N = Matrix::size;
Matrix matrix;
for(unsigned int i = 0; i < N; i++){
for(unsigned int j = 0; j < N; j++){
matrix.m[i * N + j] = 0;
for(unsigned int z = 0; z < N; z++){
matrix.m[i * N + j] += a.m[i * N + z] * b.m[z * N + j];
}
}
}
return matrix;
}
To statically determine the size N of the matrix, the class template needs to have a nested constant expression value size, e.g.:
template <unsigned int N>
class MatrixN {
public:
static constexpr unsigned int size = N;
// ...
};
This code may work. But you should know this is very very dangerous.
MatrixN<3> tmp_scoped_var = this->rotation * input.rotation;
Matrix3 &rotation = reinterpret_cast<Matrix3 &>(tmp_scoped_var);
rotation.rotateX(1.1); // Call the method of B
Because tmp_scoped_var hold the data returned by MatrixN<N> 's operator *. So the memory will be freed while out of the scope. This code tells the compile to force using Matrix3 's method on the MatrixN<N> variable. The memory layouts of Matrix3 and MatrixN<N> are identical, otherwise, the program may crash due to segment fault.
According to you code, you may desire to add some particular method while the template parameter N equals 3. So class template specialization could be used.
template <>
class MatrixN<3> {
public:
float m[3*3];
MatrixN(){}
virtual ~MatrixN(){}
void identify();
MatrixN& operator=(const MatrixN<3>& b);
public:
void rotateX(const float radians);
void rotateY(const float radians);
void rotateZ(const float radians);
};
I am trying to use a symMatrixBlock representation for the cloth simulation.
The following class stores a symmetric matrix nxn who's each element is a 3x3 matrix (represented as Mat33 class)
class SymMatrixBlocks
{
public:
int size;
int *rowstart;
std::vector<int> col_lookup;
std::vector<Mat33 *> matBlock;
bool bAllZero;
public:
SymMatrixBlocks(int size);
SymMatrixBlocks(const SymMatrixBlocks &src);
~SymMatrixBlocks();
void Zero(void);
SymMatrixBlocks& operator=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator+=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator-=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator*=(double con);
Mat33* getMatBlock(int row, int col);
void SetDiag(DiagonalMatrix &src, DiagonalMatrix &ret);
void print();
Mat33* operator() (int row, int col);
};
inline const SymMatrixBlocks operator +(const SymMatrixBlocks &lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(lhs) += rhs;
}
inline const SymMatrixBlocks operator -(const SymMatrixBlocks &lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(lhs) -= rhs;
}
inline const SymMatrixBlocks operator *(const SymMatrixBlocks &lhs, double rhs)
{
return SymMatrixBlocks(lhs) *= rhs;
}
inline const SymMatrixBlocks operator *(double lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(rhs) *= lhs;
}
}
SymMatrixBlocks& SymMatrixBlocks::operator+=(const SymMatrixBlocks &src)
{
if (size != src.size)
return *this;
if (src.bAllZero)
return *this;
int i, j, start, length;
for (i = 0; i<src.size; i++)
{
start = src.rowstart[i];
length = src.rowstart[i + 1] - start;
for (j = 0; j<length; j++)
(*((*this)(i, src.col_lookup[start + j]))) += (*(src.matBlock[start + j]));
}
return *this;
}
Mat33* SymMatrixBlocks::operator() (int row, int col)
{
int i, start, l, length;
bAllZero = false;
if (row > col)
{
start = row;
row = col;
col = start;
}
start = rowstart[row];
length = rowstart[row + 1] - start;
for (l = 0; l<length; l++)
if (col_lookup[start + l] == col)
break;
if ((length != 0) && (l != length))
{
return matBlock[start + l];
}
else
{
for (l = 0; l<length; l++)
if (col_lookup[start + l] >= col)
break;
col_lookup.insert(col_lookup.begin() + start + l, col);
Mat33 *tempmat = new Mat33();
matBlock.insert(matBlock.begin() + start + l, tempmat);
for (i = row + 1; i <= size; i++)
rowstart[i]++;
return matBlock[start + l];
}
}
when I run the following line it gives memory leakage. Can anyone spot it out?
*tm1 = *df_dx * h; // all these are object of the SymMtrixBlocks class.