I have a class that defines a matrix of dimensions mxn like this:
class Matrix{
protected:
int m;
int n;
double* mat:
public:
// accessors, constructors, destructors, etc.
void assignvalue(int, int, double);
}
Right now if I need to assign a value on position i,j I have a function assignvalue that takes the positions i, j and does the magic and assigns a double value to that position. However, it would be really nice if I could assign a value like you do in matlab or in R.
mymatrix(i,j) = 1.0;
Can you give me a hint on what operator(s) I need to overload? Thanks.
Assuming your m represents the height of your Matrix and n represents the width, overloading operator() this way should do the trick:
double& Matrix::operator()(size_t i, size_t j)
{
return mat[i*m+j];
}
const double& Matrix::operator()(size_t i, size_t j) const
{
return mat[i*m+j];
}
This way, you can write something like this:
void f(Matrix & mymatrix ) {
mymatrix(2, 3) = 5.0; // Calls the first function
// ...
}
void f(Matrix const & m) {
double a = m(1, 5); // Calls the second one
//...
}
Related
I am currently porting some C code I wrote to C++ for fun. I am struggling with a malloc() call I make in C, with h and w being constants for simplicity reasons, but later exchanged with runtime constants:
double (*g2)[h][w] = malloc(h * w * sizeof(double));
In C, this is an implicit conversion of a void*, and this of course doesn't fly with C++.
I already tried casting this with reinterpret_cast<double[h][w]>, but this is still an invalid cast.
I was wondering, how can I make this work in C++ since this would save me a lot of work?
As an alternative I'll probably use a matrix class with indirection:
struct Matrix : std::vector<double> {
unsigned matSize;
std::vector<double*> indirection;
Matrix() : matSize(0) {}
Matrix(unsigned n) : matSize(n) {
resize(n*n);
indirection.resize(n);
for(unsigned i = 0; i < n; ++i) {
indirection[i] = &(*this)[i*n];
}
}
double& operator()(unsigned i, unsigned j) {
return indirection[i][j];
}
const double& operator()(unsigned i, unsigned j) const {
return indirection[i][j];
}
};
Porting involves more than just making it work, line by line, so:
C:
double (*g2)[h][w] = malloc(h * w * sizeof(double));
...
g2[y][x] = ...;
C++:
std::vector<double> g2(h*w);
...
g2[y+x*h] = ...; // or
g2[y*w+x] = ...;
Using that syntax is inconvenient for accessing elements so you might want to wrap it inside a simple class. Example:
#include <iostream>
#include <iterator>
#include <vector>
class arr2d {
public:
arr2d(size_t h, size_t w) : data_(h * w), w_(w) {}
inline double& operator()(size_t y, size_t x) {
return data_[y * w_ + x];
}
inline double operator()(size_t y, size_t x) const {
return data_[y * w_ + x];
}
// getting pointer to a row
inline double* operator[](size_t y) {
return &data_[y * w_];
}
inline double const* operator[](size_t y) const {
return &data_[y * w_];
}
inline size_t width() const { return w_; }
private:
std::vector<double> data_;
size_t w_;
};
int main() {
arr2d g2(3, 4);
g2(2, 3) = 3.14159;
// alternative access:
g2[1][2] = 1.23456;
std::cout << g2[2][3] << "\n";
double* row = g2[2];
std::copy(row, row + g2.width(), std::ostream_iterator<double>(std::cout, ", "));
std::cout << "\n";
}
Output:
3.14159
0, 0, 0, 3.14159,
A non-initializing version could look like:
class arr2d {
public:
arr2d(size_t h, size_t w) : data_(new double[w * h]), w_(w) {}
inline double& operator()(size_t y, size_t x) { return data_[y * w_ + x]; }
inline double operator()(size_t y, size_t x) const { return data_[y * w_ + x]; }
inline double* operator[](size_t y) { return &data_[y * w_]; }
inline double const* operator[](size_t y) const { return &data_[y * w_]; }
inline size_t width() const { return w_; }
private:
std::unique_ptr<double[]> data_;
size_t w_;
};
But note that the
std::copy(row, row + g2.width(), std::ostream_iterator<double>(std::cout, ", "));
from the first example would lead to undefined behaviour.
Also note that this version will delete the copy constructor and copy assignment operator. You'll have to implement them yourself if you need them.
The creation time for the non-initializing version is of course hard to beat with any initializing version, but for access times, one might think that a lookup table, or indirection as you call it, for the rows would speed up things compared to doing the multiplication and addition in one go.
My results:
8x8 http://quick-bench.com/f8zcnU9P8oKwMUwLRXYKZnLtcLM
1024x1024 http://quick-bench.com/0B2rQeUkl-WoqGeG-iS1hdP4ah8
4096x4096 http://quick-bench.com/c_pGFmB2C9_B3r3aRl7cDK6BlxU
It seems to vary. The lookup version is faster for the 4096x4096 matrix but the naive version is faster for the two smaller ones. You need to compare using sizes close to what you'll be using and also check with different compilers. I sometimes get completely opposite "winners" when changing compiler.
Since you don't mind inheriting from std::vector or keeping extra data for a lookup-table, this could be an option. It seems to outperform the other versions slightly.
class arr2d : protected std::vector<double*> {
public:
using std::vector<double*>::operator[]; // "row" accessor from base class
arr2d(size_t h, size_t w) :
std::vector<double*>(h),
data_(new double[w * h]),
w_(w),
h_(h)
{
for(size_t y = 0; y < h; ++y)
(*this)[y] = &data_[y * w];
}
inline size_t width() const { return w_; }
inline size_t height() const { return h_; }
private:
std::unique_ptr<double[]> data_;
size_t w_, h_;
};
Here are Philipp-P's (OP:s) own measurements for the different 2D-array implementations:
8x8 http://quick-bench.com/vMS6a9F_KrUf97acWltjV5CFhLY
1024x1024 http://quick-bench.com/A8a2UKyHaiGMCrf3uranwOCwmkA
4096x4096 http://quick-bench.com/XmYQc0kAUWU23V3Go0Lucioi_Rg
Results for 5-point stencil code for the same versions:
8x8 http://quick-bench.com/in_ZQTbbhur0I4mu-NIquT4c0ew
1024x1024 http://quick-bench.com/tULLumHZeCmC0HUSfED2K4nEGG8
4096x4096 http://quick-bench.com/_MRNRZ03Favx91-5IXnxGNpRNwQ
In C++ it's not advised to manually allocate memory unless necessary. Let the standard library and templates do the work for you.
They can be very useful and are great to learn if you want to get into C++! You can save a lot of time this way and write some better code.
For example, what is this data type used for? If it fits for your usage, you may instead consider creating a 2D array using std::array:
std::array<std::array<double, w>, h>
If you need to re-size the arrays regularly, std::vector could be used instead. It has effectively the same performance as an array, given that is is all it is under the hood. You can reserve() or resize() as necessary and push_back uses a 1.5x increasing scheme and is good at its job.
EDIT: Since size is known, arrays may be better here. Taken suggestion from comments.
I recommend you using std::vector. Just wrap it if you want 2D array syntax.
#include <iostream>
#include <vector>
class Array2D {
std::vector<double> _v;
size_t _width;
size_t _height;
public:
Array2D(size_t height, size_t width, double initVal = 0.0)
: _v(width * height, initVal),
_width(width),
_height(height)
{}
double* operator[](size_t y) {
return _v.data() + y * _width;
}
};
int main(int, char**) {
size_t rows = 5;
size_t cols = 3;
Array2D a(rows, cols, 0.2);
for (size_t i = 0; i < cols; ++i)
a[4][i] = -0.1 * i;
std::cout << a[4][2] << std::endl; //-0.2
return 0;
}
You can do this, which should work in both C and C++:
double *g2 = (double*) malloc(h * w * sizeof(double));
Though, as others have stated, this is not the way to approach this issue in C++ in general. For instance, you should use a std::vector instead:
#include <vector>
std::vector<double> g2(h * w);
In both cases, you end up with a dynamically allocated 2D array of doubles in a single contiguous block of memory. And as such, you need to then use g2[(row*w)+col] syntax to access the individual elements, where 0 <= row < h and 0 <= col < w.
I'm learning C++, so please be patient with me.
I have a std::valarray in which there are double elements and I consider it as a 2D matrix.
class Matrix {
valarray<double> elems;
int r, c;
public:
/* type? operator[](int r) { return ? } */
//...
}
I want to overload the operator[], so that I can get a row of the matrix, and after that, I want have the m[r][c] access operator.
Is there any way to get a row, as a sequence of double using std::slice in the valarray, so that if I change a value, it is changed also in the matrix?
I've read this definition in valarray:
std::slice_array<T> operator[]( std::slice slicearr );
My operator[] must have std::slice_array<double>& as returned type?
Thanks.
I don't think std::slice and std::slice_array is what you're looking for, especially the latter is nothing but a helper type with a very limited public interface. You can instead return an proxy object. Here's a possible example of how to implement that.
class Matrix {
/* ... */
class RowProxy {
public:
RowProxy(std::valarray<double>& elems, int c, int row) :
elems(elems), c(c), row(row) {}
double& operator[](int j)
{
return elems[row*c + j];
}
private:
std::valarray<double>& elems;
int row;
int c;
};
RowProxy operator[](int i)
{
return RowProxy(elems, c, i);
}
};
This way, you can access the data with two operator[].
Matrix m(2, 4); // Assuming the ctor initializes elemens with row*column
m[0][0] = 1.234;
m[1][0] = 2.234;
m[1][3] = -52.023;
Note that both Matrix and RowProxy are missing overloads and proper handling for const-ness, and variable names are poor. Also, you might want to think about an out-of-bounds error handling strategy. But it may serve as a starting point for your implementation.
Title may not make any sense but I dont really know how to explain this.
I have a class called polynomial and lets say I defined a polynome called p1 which is 2x+4. What I want to do is calculate p1(5) directly. I dont want anything like double calculate (polynomial) etc I want to be able to calculate my polynom with p1(x).
I hope my question is clear
Overload the function-call operator:
struct polynomial
{
double a, b;
polynomial(double m, double n) : a(m), b(n) { } // represents "a * x + b"
double operator()(double x) const
{
return a * x + b;
}
};
Usage:
polynomial p(2.5, 3.8);
double val = p(1.0);
By overloading operator() you can "call" an object just like you would call a function:
struct polynomial {
int operator()(int x)
{
/* calculate */
}
};
int main()
{
polynomial p;
int x = p(5);
}
I am implementing a tridiagonal matrix and I have to be as efficient as possible. Obviously I will only hold the elements that contain data. I overloaded the operator() to act as an indexer into the matrix, but I want this operator to return a reference so that the user can modify the matrix. However, I cannot just return 0; for the non-tridiagonal elements since the zero is not a reference. How do I let the user modify the data on the tridiagonal, but when the operator() is used to inspect a non-tridiagonal element, only return 0 instead of a reference to 0?
below is the related class definition
template <class T>
class tridiagonal
{
public:
tridiagonal();
~tridiagonal();
T& operator()(int i, int j);
const T& operator()(int i, int j) const;
private:
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
One trick you can use is to have the non-const operator() (int, int) method return a little helper object. The helper is used to differentiate between assigning into the matrix and just pulling out a value. This lets you have different behavior for the two operations. In particular, you can throw if someone tries to assign into a value that must be zero.
This code at least compiles for me in VC10, but obviously doesn't link.
template <class T>
class tridiagonal
{
public:
// Helper class that let's us tell when the user is
// assigning into the matrix and when they are just
// getting values.
class helper
{
tridiagonal<T> &m_parent;
int m_i, m_j;
public:
helper(tridiagonal<T> &parent, int i, int j)
: m_parent(parent), m_i(i), m_j(j)
{}
// Converts the helper class to the underlying
// matrix value. This doesn't allow assignment.
operator const T & () const {
// Just call the const operator()
const tridiagonal<T> &constParent = m_parent;
return constParent(m_i, m_j);
}
// Assign a value into the matrix.
// This is only called for assignment.
const T & operator= (const T &newVal) {
// If we are pointing off the diagonal, throw
if (abs(m_i - m_j) > 1) {
throw std::exception("Tried to assign to a const matrix element");
}
return m_parent.assign(m_i, m_j, newVal);
}
};
tridiagonal();
~tridiagonal();
helper operator()(int i, int j)
{
return helper(*this, i,j);
}
const T& operator()(int i, int j) const;
private:
T& assign(int i, int j, const T &newVal);
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
int main(int argc, const char * argv[])
{
tridiagonal<double> mat;
std::cout << mat(0,0) << std::endl;
const tridiagonal<double> & constMat = mat;
std::cout << mat(2,3) << std::endl;
// Compiles and works
mat(2,3) = 10.0;
// Compiles, but throws at runtime
mat(1, 5) = 20.0;
// Doesn't compile
// constMat(3,3) = 12.0;
return 0;
}
It's been a while since I've done this, so you may find that you need to add a bit more to the helper class, depending on how you use the matrix.
Actually working through this is a good C++ exercise. :)
The issue you have here is an inappropriate interface. If your definition of a matrix is a 2D array of numbers such that every element of the matrix can be individually set, then a sparse, tridiagional matrix is paradoxically not a matrix (just as a square is not a modifiable rectangle - a classic example of inappropriate inheritance that doesn't obey the Liskov Substitution Principle).
In short, you'd be better off changing your interface to suit sparse, tridiagonal matrices rather than trying to hack it to work with the interface you've got. That said, if you must do it this way, then you are probably better off doing two things:
Modifying your const accessor to return T instead of const T& (I'm assuming we're only dealing with matrices of numbers here). Then you can just return 0 for the elements off the diagonal.
Modifying your non-const accessor to return a reference to a dummy element for locations off the diagonal, and crossing your fingers :) Alternatively, you could change the specification to throw in such cases, but that might be a little unfriendly.
One other alternative (short of reworking the interface properly) might be to return proxy objects instead of Ts. The proxy for dummy elements would then throw when you try and set the value using it.
Returning by reference requires that you return a valid object of the specified type. The simplest way to accomplish what you want is to keep a static T object that represents 0, and return it instead.
Alternatively, you could return a pointer.
Just add an extra member representing some dummy value and make sure it always reads as 0.
template<typename T>
class tridiagonal
{
// usual stuff...
T& operator() (int j, int j)
{
// if not explicitly stored, reset to default before returning.
return stored(i,j)? fetch(i,j) : (m_dummy=T());
}
private:
// dummy element used to "reference" elements outside the 3 diagonals.
T m_dummy;
// check if (i,j) is on 3 diagonals.
bool stored (int i, int j) const;
// access element on 3 diagonals. precondition: stored(i,j)==true.
T& fetch (int i, int j);
//holds data of just the diagonals
T * m_upper;
T * m_main;
T * m_lower;
};
Note that technically speaking, someone could trick you as such:
tridiagonal<int> m(4,4);
T * dummy = &m(3,0); // *dummy == 0.
*dummy = 1; // *dummy == 1.
std::cout << *dummy; // prints 1.
But that's not necessarily a problem.
I was trying to make a function which takes a matrix as input and outputs some function of it in C++. But I want it to work on arbitrary size mxn matrix. i.e. I cannot specify in the arguments of the function the values of n (double matrix[][n]) . Because n will be arbitrary.
Is there any way I can pass on an arbitrary mxn 2 dimensional array to a function?
Thanking you in advance.
-indiajoe
template <typename T, size_t W, size_t H>
void foo(T (&array)[W][H]) {
// Do stuff with array here
}
There is more than one way to do it. The best way is probably to define a matrix class and to pass a const reference to an instance.
class matrix
{
double* values;
size_t m;
size_t n;
public:
matrix(size_t m_, size_t n_)
: m(m_), n_(n)
{
values = new double[m * n];
}
~matrix()
{
delete[] values;
}
double& operator(size_t i, size_t j)
{
assert(i < m);
assert(j < n);
return values[i + m * j];
}
const double& operator(size_t i, size_t j) const
{
assert(i < m);
assert(j < n);
return values[i + m * j];
}
private:
matrix(const matrix&);
matrix& operator =(const matrix&);
};
void function(const matrix& matrix);
If you don't want to use a class, and your data is stored linearly (as in my matrix class), you can simply pass a pointer to a double, and the dimensions:
void function(double* values, size_t m, size_t n);
If you really want to use double[m][n] and have a function accepting any matrix size, you can convert it manually to a double**, by doing something like that:
void function(double** lines, size_t m, size_t n);
void client()
{
const size_t m = ...;
const size_t n = ...;
double matrix[m][n];
double* temporary[m];
for (size_t i = 0; i < m; ++ i) {
temporary[i] = &matrix[i][0];
}
function(temporary, m, n);
}
Or, using a template function to do the conversion:
void function(double** array, size_t m, size_t n);
template < size_t M, size_t N >
void function(double array[M][N]) {
double* temporary[M];
for (size_t i = 0; i < M; ++ i) {
temporary[i] = &array[i][0];
}
function(temporary, M, N);
}
This is because an array can only decay once to a pointer (that is double[n] decay to double* but double[m][n] decay to double*[n]).
using the Standard C++ Library, you could do that:
typedef std::vector<double> Dim;
typedef std::vector<Dim> Matrix;
void workOnMatrix(Matrix& matrix)
{
}
EDIT: I remove the reference to STL since SGI's STL and the Standard C++ Library are not the same things. So much different it seems that they must not be taken one for another.
You could do it Tomalak's way, but I certainly wouldn't recommend it. You could never call that function from within another that wasn't also a template if the array was passed through params. This means almost your entire program would have to be templated code. OK, in theory, but generally impractical.
You can't use the double** interface as you've found out. You could cast to that type but then you also need the size information to be passed in so that you can:
my_ptrptr[row * col_size][col];
You have to be explicit about the dimensions like this because the compiler no longer knows what it needs to.
The best answer to your problem is to not do it that way. Leverage the STL so that you don't have to deal with hokey crap like this. Use Stephane's answer.
Yet another thing you can do though, if you're going to use templates anyway, is to write it to be generic:
template < typename Iter >
void fun(Iter begin, Iter end)
{
// begin[x][y]... (*begin)[y]...++begin, etc...
}
...
double arr[arr_row_count][arr_col_count];
fun(arr, arr+arr_row_count);
This one has the major benefit of working with ANYTHING that looks like an array of arrays. This means it would make an excellent 'interim' method that you can use with your double[][] types until such time as you can begin using something better like the std::vector and/or boost::array. Do it Tomalak's way and you won't be able to make this change later...yet another reason not to use that method.