I just wanted to know how to overload the operator [] to acces a matrix within a class, and I found how to that here.
But, I have a question about this: Which way of changing a matrix will be more efficient?
1: Overloading the operator []: (code extracted from the previous link)
class CMatrix {
public:
int rows, cols;
int **arr;
public:
int* operator[]( int const y )
{
return &arr[0][y];
}
....
Edit: I relied too much on the other example: Should it work this way?
int* operator[]( int const x )
{
return &arr[x];
}
2:Using a "normal" method:
class CMatrix {
public:
int rows, cols;
int **arr;
public:
void changematrix( int i, int j, int n)
{
arr[i][j]=n;
}
...
Edit: Fixed const on changematrix
Write correct, readable code and let the compiler worry about efficiency.
If you have performance problems, and if when you run a profiler to measure the performance (which you MUST do before trying to optimize) this code shows up as a performance issue, then you can:
1) Examine the assembly language interpretation of the code generated by the compiler with full optimization enabled, or
2) Try it both ways, measure, and pick the faster one.
The results will be highly dependent on the compiler you are using and the flags you specify for that compiler.
Neither method will work as you have declared
int **arr;
gives no row length information for:
return &arr[0][y];
arr[i][j]=n;
I would go for a third option, using operator() instead of operator[]:
int& operator()(size_t i, size_t j) {
return arr[i][j];
}
int operator()(size_t i, size_t j) const {
return arr[i][j];
}
The user will then do:
CMatrix m = ...
m(1,2) = 5;
std::cout << m(1,2);
Other than that, I would really consider whether the way of laying out the data internally the the most efficient. Is this a jagged array? Or do all rows have the same width? If this represents a rectangle shaped array (i.e. all rows have the same number of columns) you might be better off storing all elements in a single 1D array, and using some basic arithmetic to locate the correct element.
Related
I got here trying to transpose a matrix in O(1). So right now I have something like this:
#include <vector>
template <class T>
class Matrix { //intended for math matrix
public:
Matrix(int Rows, int Cols){matrix = vector<vector<T> >(Rows, vector<T>(Cols,0)); transpose = false; cols = Cols; rows = Rows;}
Matrix(const Matrix<T> &M){matrix = M.matrix; transpose = M.transpose; cols = M.cols; rows = M.rows;}
~Matrix(){}
void t(){
transpose = !transpose;
swap(cols,rows);
}
T& operator()(int row, int col){
if(transpose)
return matrix[col][row];
else
return matrix[row][col];
}
private:
vector<vector<T> > matrix;
bool transpose;
int cols;
int rows;
};
In that code I have what I want: t() is O(1) and operator() is also O(1). But operator() is used a lot and I want to take away the if.
So, to verify if I can improve performance I want to have something like this:
#include <vector>
template <class T>
class Matrix { //intended for math matrix
public:
Matrix(int Rows, int Cols){matrix = vector<vector<T> >(Rows, vector<T>(Cols,0)); transpose = false; cols = Cols; rows = Rows;}
Matrix(const Matrix<T> &M){matrix = M.matrix; transpose = M.transpose; cols = M.cols; rows = M.rows;}
~Matrix(){}
T& originalShape(int row, int col){return matrix[row][col];}
T& transposedMatrix(int row, int col){return matrix[col][row];}
void t(){
transpose = !transpose;
swap(cols,rows);
if(transpose)
&operator() = &transposedMatrix;
else
&operator() = &originalShape;
}
T& operator()(int row, int col){return matrix[row][col];}
private:
vector<vector<T> > matrix;
bool transpose;
int cols;
int rows;
};
Of course, that doesn't work. And I didn't find anything useful for this case.
More info about performance impact of t() and operator():
I read that some libraries both use t() in O(1) and O(rows*cols), according to what is going to be used the matrix for. But doing t() in O(1) seems to be a good first step. If then I call a method I know it would access row by row, then I could do the copy transpose at that moment.
And for taking the if: the idea is to put all the weight of the operation in t() and to have the fastest operator(), because t() would be call once in a while and operator() a lot. I also want to know how to do this because it might become helpful in another situation.
The question
Maybe i lack enough English to make this clear: the objective of the question is to find a good way to change the behavior of operator(). Not to improve Matrix() (advice is much appreciated though), nor to discard any way of changing the behavior of operator() just because it might not be better than the if. Ultimately, I will analyze, code and post the one that has the best performance between what i have and what i get as answers. But to know what has better performance i need those codes/algorithms/patterns/whatever, and I think this may help other people in different but similar situations.
If you store your matrix as a single vector, you can write the indexing function like this:
T& operator()(int row, int col){
return matrix[col*colstep + row*rowstep];
}
Initially rowstep is 1 and colstep is rows. The transpose operator swaps these two values and the sizes.
You do have one extra multiplication, you'll have to measure if that is better or worse than the extra if. Note that branch prediction will guess right most of the time if accessing many/all matrix elements in a loop.
You will still have the problem of accessing data in a non-optimal order, it's worth while to write algorithms taking into account the storage order.
Basically, my problem is: I have the user to define the size (N,M) of a 2D array and then I declare:
int matrix[N][M];
then I need to pass this uninitialized matrix to a function that reads some data from a .csv file and puts it into the matrix, so I tried:
void readwrite(int &matrix[N][], const int N, const int M){....};
int main(){
....
cin>>N;
cin>>M;
int matrix[N][M];
readwrite(matrix,N,M);
};
However, when i compile it, it gives me the following error: "N was not declared in this scope".
Any ideas of how to make this work?
Thank y'all!
What The OP is trying is so annoyingly difficult to get right and the benefits of pulling it off are so minuscule compared to the costs that... Well, I'll quote from the Classics.
The only winning move is not to play.
-Joshua, WarGames
You cannot safely pass a dynamically allocated 2D array in C++ into a function because you always have to know at least one dimension at compile time.
I could point over at Passing a 2D array to a C++ function because that looks like a good duplicate. I won't because it's referring to statically allocated arrays.
You can play silly casting games to force the array into the function, and then cast it back on the inside. I'm not going to explain how to do this because it is epic-class stupid and should be a firing offense.
You can pass a pointer to a pointer, int **, but the construction and destruction logic is a grotesque set of new and loops. Further, the end result scatters the allocated memory around the RAM, crippling the processors attempts at prediction and caching. On a modern processor if you can't predict and cache, you are throwing away the greater part of your CPU's performance.
What you want to do is stay one dimensional. A 1D array is easy to pass. The indexing arithmetic is dead simple and easy to predict. It's all one memory block so cache hits are more likely than not.
Making a 1D array is simple: Don't. Use std::vector instead.
std::vector<int> arr(rows*columns);
If you have to because the assignment spec says "No Vectors!" Well you're stuck.
int * arr = new int[rows*columns];
Note I'm using rows and columns not M and N. When faced with M and N which is which? Who knows, who cares, and why do this to yourself in the first place? Give your variables good, descriptive names and enjoy the time savings of being able to read your code when you are debugging it later.
The guts of usage are identical with array and vector:
int test = arr[row * columns + column];
Will recover the element in 2D space at [row][column]. I shouldn't have to explain what any of those variables mean. Death to M and N.
Defining a function is:
void function (std::vector<int> & arr, size_t rows, size_t columns)
or (yuck)
void function (int * arr, size_t rows, size_t columns)
Note that rows and columns are of type size_t. size_t is unsigned (a negative array size is not something you want, so why allow it?) and it is guaranteed to be big enough to hold the largest possible array index you can use. In other words it is a much better fit than int. But why pass rows and columns everywhere? The smart thing to do at this point is make a wrapper around an the array and its control variables and then bolt on a few functions to make the thing easier to use.
template<class TYPE>
class Matrix
{
private:
size_t rows, columns;
std::vector<TYPE> matrix;
public:
// no default constructor. Matrix is BORN ready.
Matrix(size_t numrows, size_t numcols):
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
// vector handles the Rule of Three for you. Don't need copy and move constructors
// a destructor or assignment and move operators
// element accessor function
TYPE & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
// constant element accessor function
TYPE operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
// stupid little getter functions in case you need to know how big the matrix is
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
// and a handy-dandy stream output function
friend std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (int i = 0; i < in.getRows(); i++)
{
for (int j = 0; j < in.getColumns(); j++)
{
out << in(i,j) << ' ';
}
out << '\n';
}
return out;
}
};
Rough bash-out of what the array version would have to look like just to show the benefits of allowing vector to do its job. Not tested. May contain howlers. The point is a lot more code and a lot more room for error.
template<class TYPE>
class ArrayMatrix
{
private:
size_t rows, columns;
TYPE * matrix;
public:
ArrayMatrix(size_t numrows, size_t numcols):
rows(numrows), columns(numcols), matrix(new TYPE[rows * columns])
{
}
// Array version needs the copy and move constructors to deal with that damn pointer
ArrayMatrix(const ArrayMatrix & source):
rows(source.rows), columns(source.columns), matrix(new TYPE[rows * columns])
{
for (size_t i = 0; i < rows * columns; i++)
{
matrix[i] = source.matrix[i];
}
}
ArrayMatrix(ArrayMatrix && source):
rows(source.rows), columns(source.columns), matrix(source.matrix)
{
source.rows = 0;
source.columns = 0;
source.matrix = nullptr;
}
// and it also needs a destructor
~ArrayMatrix()
{
delete[] matrix;
}
TYPE & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
TYPE operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
// and also needs assignment and move operator
ArrayMatrix<TYPE> & operator=(const ArrayMatrix &source)
{
ArrayMatrix temp(source);
swap(*this, temp); // copy and swap idiom. Read link below.
// not following it exactly because operator=(ArrayMatrix source)
// collides with operator=(ArrayMatrix && source) of move operator
return *this;
}
ArrayMatrix<TYPE> & operator=(ArrayMatrix && source)
{
delete[] matrix;
rows = source.rows;
columns = source.columns;
matrix = source.matrix;
source.rows = 0;
source.columns = 0;
source.matrix = nullptr;
return *this;
}
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
friend std::ostream & operator<<(std::ostream & out, const ArrayMatrix & in)
{
for (int i = 0; i < in.getRows(); i++)
{
for (int j = 0; j < in.getColumns(); j++)
{
out << in(i,j) << ' ';
}
out << std::endl;
}
return out;
}
//helper for swap.
friend void swap(ArrayMatrix& first, ArrayMatrix& second)
{
std::swap(first.rows, second.rows);
std::swap(first.columns, second.columns);
std::swap(first.matrix, second.matrix);
}
};
Creating one of these is
Matrix<int> arr(rows, columns);
Now passing the array around is
void func(Matrix & arr);
Using the array is
int test = arr(row, column);
All of the indexing math is hidden from sight.
Other references:
What is the copy-and-swap idiom?
What is The Rule of Three?
int &matrix[N][] - N has to be a compile-time constant, not just const and not at all a parameter. And reference to an array is declared like: int (&matrix)[size]
Try passing int **matrix, and you'll also need to change the way you create this array. Variable lenght arrays are not supported in C++, you'll need to allocate it's memory dynamically. Or rather, stick with std::vector, std::array if you knew the sizes at compile-time.
I have a two dimensional smart pointer array of doubles. I can assign values to it, and display it, but I am having trouble passing it to a function that takes double** as an input. A simple get() does not work.
#include <iostream>
#include <memory>
using namespace std;
# define DIM1 3
# define DIM2 4
void funcCall(double** item)
{
cout<< "Test function.";
}
int main() {
std::unique_ptr<std::unique_ptr<double[]>> myArray(new std::unique_ptr<double[]>[DIM1]);
for (int i = 0; i < DIM1; i++)
{
myArray.get()[i].reset(new double[DIM2]);
}
std::cout<<"Assign values"<<std::endl;
for (int i = 0; i < DIM2; i++)
{
for (int j = 0; j < DIM1; j++)
{
myArray.get()[j][i] = (j+1)*(i+1);
}
}
funcCall(myArray.get());
return 0;
}
When I compile this, I get:
error: cannot convert 'std::unique_ptr<std::unique_ptr<double []> >::pointer {aka std::unique_ptr<double []>*}' to 'double**' for argument '1' to 'void funcCall(double**)' funcCall(myArray.get())
void funcCall(std::unique_ptr<std::unique_ptr<double[]>> & arr)
Should do what you want, but...
but...
It sounds like you are trying to reinvent the wheel. Don't do that. Unless this is for an assignment or personal education, in that case go nuts.
Instead, use one of the built-in containers.
Because DIM1 and DIM2 are constant, you can use
std::array<std::array<double, DIM2>,DIM1> myArray;
and
void funcCall(std::array<std::array<double, DIM2>,DIM1> arr)
But odds are pretty good you want a dynamic solution. In that case, try
std::vector<std::vector<double>> myArray(DIM1, std::vector<double>(DIM2));
and
void funcCall(std::vector<std::vector<double>> arr)
but...
This is a sucker bet, to be honest. An array of arrays or a vector of vectors are not contiguous in memory so the computer has to hop around in storage, wasting time on unnecessary cache misses and the time spent loading and possibly reloading cache often take longer than the computations involved. All the 133t math in the world can't help you at this point because you've become gated by IO, and IO is sssssssssslllloooowwwwwwww.
What you really want is one nice 1 dimensional array that's indexed manually. with row * number of columns + column. Sure, manual index looks like extra work, but stop and think: How much math is the compiler doing in the background to make you array work, hmmm? Probably about the same. You just don't get to see it.
Let's stuck with std::vector for now, but the same applies to std::array or even a good ol' static array or a dynamic inside a smart pointer.
std::vector<double> myArray(DIM1*DIM2);
Using this is relatively simple:
myArray[row*DIM2 + column];
The function is:
void funcCall(std::vector<double> arr)
But this is easily wrapped in a class and simplified further:
class matrix
{
private:
std::vector<double> myArray;
size_t nrRows;
size_t nrColumns;
public:
matrix(size_t rows, size_t columns):
myArray(rows*columns), nrRows(rows), nrColumns(columns)
{
}
double& operator()(size_t row, size_t column)
{
return myArray[row* nrColumns + column];
}
double operator()(size_t row, size_t column) const
{
return myArray[row* nrColumns + column];
}
};
Construction:
matrix mat(DIM1, DIM2);
and usage:
double d = mat(1,2);
or
mat(2,1) = 3.14;
The types of the call and the function header don't match. You can't treat a unique_ptr as a regular pointer.
One solution is to change your function definition to:
void funcCall(std::unique_ptr<double[]> *item)
I am using trying to solve the Shortest Path problem in C++. For that I have created the following Graph() constructor.
Graph::Graph(int NumberOfVertices){
this->NumberOfVertices=NumberOfVertices;
cout<<"Graph()"<<endl;
//declaring the weight matrix
WeightMatrix=new int*[NumberOfVertices];
for(int a=0;a<NumberOfVertices;a++)
WeightMatrix[a]=new int[NumberOfVertices];
//initialising the weight matrix
WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
ShortestPathArray=new int[NumberOfVertices];
}
I have two questions.
Why is a simple declaration like
WeightMatrix=new int[NumberOfVertices][NumberOfVertices] not allowed? I tried doing so but there were errors. I found the solution online, but am not able to understand it.
The initialization step is not working. The code doesn't proceed further than this statement WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
When I comment out this step everything works fine.
Question #1:
The type of WeightMatrix is int**, so you cannot initialize it with new int[...].
As you seem to have already fixed in your code, the right way is to initialize it with new int*[...].
Question #2:
Initializing an array to a list of values is allowed only at declaration. For example:
int WeightMatrix[M][N] =
{
{1,2,3,...},
{4,5,6,...},
...
};
So you can fix the compilation error by changing this:
WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
To this:
for (int i=0; i<NumberOfVertices; i++)
for (int j=0; j<NumberOfVertices; j++)
WeightMatrix[i][j] = 0;
Why is a simple declaration like WeightMatrix=new int[NumberOfVertices][NumberOfVertices] not allowed? I tried doing so but there were errors. I found the solution online, but am not able to understand it.
It should help to compare this to creation of an array on the stack, for which you can do:
int my_array[X][Y];
When you later say my_array[x][y], the compiler's record of the value Y is used to find the int value at address &my_array + x * Y + y. But, when you use new and specify a dimension at run-time, the compiler isn't obliged to store the dimension(s) involved - that would adversely affect run-time memory usage and performance. Without such dimensions though, the compiler can't support a [x][y] notation, so it's misleading to let you use new as if it were creating a multi-dimensional array. In practice, implementations sometimes store the single allowed array dimension in some extra memory they ask for when you use new[] so they can iterate over the right number of elements to call destructors, but they might want to avoid that for types such as int that require no destruction.
The expectation is that you'll work out the total number of elements you need:
int* weightMatrix = new int[NumberOfVertices * NumberOfVertices];
Then what's conceptually weightMatrix[x][y] can be stored at weightMatrix[x * NumberOfVertices + y] (or if you prefer weightMatrix[x + NumberOfVertices * y]).
I recommend writing a simple class that has an operator to provide a convenient notation ala matrix(x, y):
template <typename T>
class Matrix
{
Matrix(size_t X, size_t Y = X) : X_(X), Y_(Y), p_(new T[X * Y]) { }
~Matrix() { delete[] p_; }
T& operator()(size_t x, size_t y) { return p_[x * Y + y]; }
const T& operator()(size_t x, size_t y) const { return p_[x * Y + y]; }
size_t X_, Y_;
T* p_;
};
Then you can write simpler, cleaner and more robust client code:
Matrix matrix(20, 10);
matrix(4, 2) = 13;
You can also easily put checks in operator() to catch out-of-bound indexing during development and testing.
I am relatively new to C++ and still confused how to pass and return arrays as arguments. I would like to write a simple matrix-vector-product c = A * b function, with a signature like
times(A, b, c, m, n)
where A is a two-dimensional array, b is the input array, c is the result array, and m and n are the dimensions of A. I want to specify array dimensions through m and n, not through A.
The body of the (parallel) function is
int i, j;
double sum;
#pragma omp parallel for default(none) private(i, j, sum) shared(m, n, A, b, c)
for (i = 0; i < m; ++i) {
sum = 0.0;
for (j = 0; j < n; j++) {
sum += A[i][j] * b[j];
}
c[i] = sum;
}
What is the correct signature for a function like this?
Now suppose I want to create the result array c in the function and return it. How can I do this?
So instead of "you should rather" answer (which I will leave up, because you really should rather!), here is "what you asked for" answer.
I would use std::vector to hold your array data (because they have O(1) move capabilities) rather than a std::array (which saves you an indirection, but costs more to move around). std::vector is the C++ "improvement" of a malloc'd (and realloc'd) buffer, while std::array is the C++ "improvement" of a char foo[27]; style buffer.
std::vector<double> times(std::vector<double> const& A, std::vector<double> const& b, size_t m, size_t n)
{
std::vector<double> c;
Assert(A.size() = m*n);
c.resize(n);
// .. your code goes in here.
// Instead of A[x][y], do A[x*n+y] or A[y*m+x] depending on if you want column or
// row-major order in memory.
return std::move(c); // O(1) copy of the std::vector out of this function
}
You'll note I changed the signature slightly, so that it returns the std::vector instead of taking it as a parameter. I did this because I can, and it looks prettier!
If you really must pass c in to the function, pass it in as a std::vector<double>& -- a reference to a std::vector.
This is the answer you should use... So a good way to solve this one involves creating a struct or class to wrap your array (well, buffer of data -- I'd use a std::vector). And instead of a signature like times(A, b, c, m, n), go with this kind of syntax:
Matrix<4,4> M;
ColumnMatrix<4> V;
ColumnMatrix<4> C = M*V;
where the width/height of M are in the <4,4> numbers.
A quick sketch of the Matrix class might be (somewhat incomplete -- no const access, for example)
template<size_t rows, size_t columns>
class Matrix
{
private:
std::vector<double> values;
public:
struct ColumnSlice
{
Matrix<rows,columns>* matrix;
size_t row_number;
double& operator[](size_t column) const
{
size_t index = row_number * columns + column;
Assert(matrix && index < matrix->values.size());
return matrix->values[index];
}
ColumnSlice( Matrix<rows,columns>* matrix_, size_t row_number_ ):
matrix(matrix_), row_number(row_number_)
{}
};
ColumnSlice operator[](size_t row)
{
Assert(row < rows); // note: zero based indexes
return ColumnSlice(this, row);
}
Matrix() {values.resize(rows*columns);}
template<size_t other_columns>
Matrix<rows, other_columns> operator*( Matrix<columns, other_columns> const& other ) const
{
Matrix<rows, other_columns> retval;
// TODO: matrix multiplication code goes here
return std::move(retval);
}
};
template<size_t rows>
using ColumnMatrix = Matrix< rows, 1 >;
template<size_t columns>
using RowMatrix = Matrix< 1, columns >;
The above uses C++0x features your compiler might not have, and can be done without these features.
The point of all of this? You can have math that both looks like math and does the right thing in C++, while being really darn efficient, and that is the "proper" C++ way to do it.
You can also program in a C-like way using some features of C++ (like std::vector to handle array memory management) if you are more used to it. But that is a different answer to this question. :)
(Note: code above has not been compiled, nor is it a complete Matrix implementation. There are template based Matrix implementations in the wild you can find, however.)
Normal vector-matrix multiplication is as follows:
friend Vector operator*(const Vector &v, const Matrix &m);
But if you want to pass the dimensions separately, it's as follows:
friend Vector mul(const Vector &v, const Matrix &m, int size_x, int size_y);
Since the Vector and Matrix would be 1d and 2d arrays, they would look like this:
struct Vector { float *array; };
struct Matrix { float *matrix; };