I am trying to find an efficient and proper way to fill a 2D std::array matrix with an enum value. I am doing this:
#include <iostream>
#include <array>
template<class T, size_t ROW, size_t COL>
using Matrix = std::array<std::array<T, COL>, ROW>;
enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };
int main() {
const int mapX = 4;
const int mapY = 9;
// create a 5x10 2D array
Matrix<State, mapY, mapX> MapMatrix;
// fill array with State::RESERVED value
for (int y = 0; y <= mapY; y++) MapMatrix[y].fill(State::RESERVED);
std::cout << "MapMatrix contains:\n";
for (int y = 0; y <= mapY; ++y) {
for (int x = 0; x <= mapX; ++x) {
std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
}
std::cout << std::endl;
}
return 0;
}
Is the for loop I am doing the best way to fill the matrix with the enum value? Is there a way to fill the matrix during the declaration of Matrix<State, mapY, mapX> MapMatrix (like a constructor)?
Thanks!
You can't fill it on initialization unless you are filling it with zeros, or you specify every element explicitly. If you rearranged your enum so that RESERVED is zero, then you could initialize it like this:
Matrix<State, mapY, mapX> MapMatrix = {};
If you can't do that, then yes, a for loop is probably the best option. Keep it simple. But you have a few problems. First, your comment says that you are creating a 5x10 array, but you are not. You are creating a 4x9 array. If you want to create a 5x10 array, then you need to pass 5 and 10 as your template parameters. I think you're probably getting confused by the fact that the last element of an array of size N is N - 1. This off-by-one issue is only relevant to accessing elements of an array, not in specifying the size of an array.
Second, you are iterating past the end of your array, because your loop condition is y <= mapY, rather than y < mapY. But it would be better if you just used a range-for loop.
for (auto& arr : MapMatrix)
arr.fill(State::RESERVED);
I think that a loop based initialization is a good solution.
But, just for fun, I propose you another solution std::index_sequence and template pack expansion based.
A working example (with index corrected)
#include <iostream>
#include <utility>
#include <array>
template <typename T, std::size_t ROW, std::size_t COL>
using Matrix = std::array<std::array<T, COL>, ROW>;
enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };
template <typename T, std::size_t ... Rs, std::size_t ... Cl>
Matrix<T, sizeof...(Rs), sizeof...(Cl)> initMat
(T const & tVal,
std::index_sequence<Rs...> const &,
std::index_sequence<Cl...> const &)
{
auto col = std::array<T, sizeof...(Cl)>{ { ((void)Cl, tVal)... } };
return Matrix<T, sizeof...(Rs), sizeof...(Cl)>
{ { ((void)Rs, col)... } };
}
int main()
{
constexpr std::size_t mapX = 5U;
constexpr std::size_t mapY = 10U;
// create a 5x10 2D array
auto MapMatrix = initMat(State::RESERVED,
std::make_index_sequence<mapX>(),
std::make_index_sequence<mapY>());
std::cout << "MapMatrix contains:\n";
for ( auto y = 0U ; y < mapY ; ++y )
{
for ( auto x = 0U ; x < mapX ; ++x )
std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
std::cout << std::endl;
}
return 0;
}
Related
The below is the basic code. I want to make the array globally so that i don't have to call it for every function.Now how do I initialize the 2d array with -1. I tried to use memset(arr,-1,sizeof(arr)) just below line 3, but it didn't worked out, so, can anyone tell me what am I doing wrong??
#include <bits/stdc++.h>
using namespace std;
int arr[10][10];
int func(){
//this function will be using the global arr
// if(arr[x][y]!=-1)
//do something
}
int main(){
//the code
}
I do not know the good way to initialize a built-in array in place without code repetition. I do, however, know a way to initialize std::array:
#include <array>
#include <utility>
#include <cstddef>
template<size_t... Ix>
auto constexpr make1array(int v, std::index_sequence<Ix...>) {
auto populate = [](int v, size_t) { return v; };
std::array<int, 10> a = { populate(v, Ix)... };
return a;
}
template<size_t... Ix1, size_t... Ix2>
auto constexpr make2array(int v, std::index_sequence<Ix1...> seq, std::index_sequence<Ix2...>) {
auto populate = [](auto v, size_t) { return v; };
std::array<std::array<int, 10>, 10> a = { populate(make1array(v, seq), Ix2)... };
return a;
}
std::array<std::array<int, 10>, 10> arr = make2array(-1, std::make_index_sequence<10>{}, std::make_index_sequence<10>{});
This code produces an array pre-populated with -1 as the value at compile time.
The function memset won't work because memset uses bytes and many integers occupy more than one byte.
IMHO, your best source is to use std::fill.
Example:
std::fill(&arr[0][0], &arr[9][9] + 1, -1);
Otherwise, you can always fall back on the nested loop:
for (int r = 0; r < MAX_ROWS; ++r)
{
for (int c = 0; c < MAX_COLUMNS; ++c)
{
arr[r][c] = -1;
}
}
Your best bet is to let the compiler optimize the nested loops.
There may be some micro-optimizations that you could employ, but the compiler probably already has them in its tool chest.
There is no direct way to initialize raw array by values that aren't result of default initialization. One of the reasons is that array cannot be returned from function and cannot be assigned directly from anything that is not a {}-list.
Simplest way (since C++14) is to make it part of class-type with constexpr constructor. In C++111 constructor with non-empty body cannot be constexpr.
#include <iostream>
struct MinusOneArray {
static constexpr int NX = 10;
static constexpr int NY = 10;
int arr[NX][NY];
constexpr MinusOneArray() : arr() {
for(int i = 0; i < NX; ++i)
for(int j = 0; j < NY; ++j)
arr[i][j] = -1;
}
};
int main()
{
MinusOneArray a;
auto &arr = a.arr;
for(auto &line: arr) {
for(auto val: line)
std::cout << val << ",";
std::cout << std::endl;
}
}
Alternative is to use standard structure std::array and initialize it with constexpr function, how SergeyA offered.
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<int> v(100); // defined a vector of size 100
for(i=1;i<=50;i++) {
v[i]=i; // storing the values as we do in 1-d array
}
for(int i=1;i<=50;i++) {
cout<<"index="<<i<<" "<<v[i]<<"\n"; // It will give output similar
// to 1-d array
}
return 0;
}
So this is the case of one dimensional vector where index of vector is integer and the value is also integer. The above code is running fine.
But i want to take the index of a vector as pair (i,j) and the value as an integer.
See the below code for more clarification .
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<pair<int,int>> ve(make_pair(100,100));
//defined a vector of size of indices (100,100)
for(i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
ve[make_pair(i,j)]=2; // Storing value of 2 in all the
// (i,j) indices
}
}
for(int i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
cout<<ve[make_pair(i,j)]<<" ";
// Output should be 2 in all the possible pairs of (i,j)
}
}
return 0;
}
But the above code is not working :(.
Please tell me how i can fix this problem.
Vectors, like arrays, work only with integer indexes. For a vector vec, the index must be in range 0 <= index < vec.size(), otherwise it either does not compile (not convertible to unsigned int) or the behavior is undefined (out of bounds).
You have written
vector<pair<int,int>> ve
Which means that you create a vector that contains pairs, not that it is indexed by pairs.
Now, if you want a two dimensional vector, i.e. a matrix, you should check Boost matrix. You can also implement it yourself, but making it general purpose will take some effort. The basic idea is to convert the pair to an single integer value. The simplest implementation is:
template <class T>
void init_2d(std::vector<T> &vec, std::pair<unsigned, unsigned> coordinates)
{
vec.resize(coordinates.first * coordinates.second);
}
inline unsigned flatten(std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return coordinates.first * num_columns + coordinates.second;
}
template <class T>
T & get_2d(std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
template <class T>
const T & get_2d(const std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
and then use it in your code:
int main() {
std::vector<int> ve;
auto dimensions = std::make_pair(100,100);
init_2d(ve, dimensions);
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
get_2d(ve, {i,j}, dimensions.second) =j;
}
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
std::cout << get_2d(ve, {i,j}, dimensions.second) <<" ";
std::cout << '\n';
}
return 0;
}
But, instead of reimplementing existing code, you should prefer to use boost matrix. If you are trying to learn how a matrix can be implemented (which is a very good idea), then go on and try to convert the above functions+vector into a class, and put the dimensions pair into that class. Having a class, for a matrix, is better than to use separate functions. It is easier to maintain invariants for a class than for separate functions.
Note: you can use std::map<std::pair<int, int>> instead, but it will be more difficult to iterate over it and it will be much slower. If it makes your code clearer, using std::map is a good idea, but it is not clear cut whether std::map<pair<...>> is easier to work with than with std::vector + _2d functions.
I would suggest you to use map instead.
Operator [] for map takes key_type as parameter which is a container which means you can use pair object as index (called key in map), however Operator [] for vetor takes size_type as parameter which is an unsigned integer.
Your code could look like the following:
map< pair<int, int>, int > notVector;
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
notVector[make_pair(i,j)]=2; // Storing value of 2 in all the (i,j) indices
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
cout<<notVector[make_pair(i,j)]<<" ";
another solution: create your own container by aggregating a standard one.
Extremely simplified example:
#include <vector>
#include <iostream>
struct xy
{
std::size_t x, y;
};
constexpr std::size_t linear_extent(xy _)
{
return _.y * _.x;
}
constexpr std::size_t linear_position(xy _, xy extent)
{
return _.y * extent.x + _.x;
}
template<class T>
struct vector_2d
{
vector_2d(xy size, T x = T())
: extent_(size)
, storage_(linear_extent(extent_), x)
{
}
T& operator[](xy const& _)
{
return storage_[linear_position(_, extent_)];
}
T const& operator[](xy const& _) const
{
return storage_[linear_position(_, extent_)];
}
constexpr auto extent() const { return extent_; }
xy extent_;
std::vector<T> storage_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, vector_2d<T> const& v)
{
const char* sep = " [";
os << "[";
auto extent = v.extent();
for(auto y = std::size_t(0) ; y < extent.y ; ++y)
{
os << sep;
const char* sep2 = " ";
for (auto x = size_t(0) ; x < extent.x ; ++x)
{
std::cout << sep2 << v[{x, y}];
sep2 = ", ";
}
os << " ]";
sep = "\n [";
}
os << " ]";
return os;
}
int main()
{
auto v = vector_2d<int>({5, 5});
v[{1, 3}] = 8;
std::cout << v << std::endl;
}
Keep it simple
All you need is 1 (One!) C++ line: ...+ Update: Optional macro (the macro is to answer #eneski comment):
std::vector<std::vector<int>> ve(100, std::vector<int>(100, 0)); // Initialize to 0
// Turns [wr(pair)] syntax to [pair.first][pair.second] syntax:
#define wr(pr) (pr).first][(pr).second // Wrapper macro
And than use:
ve[wr(std::make_pair(i, j))] = 35; // For example
int val = ve[wr(std::make_pair(i, j))];
// Or:
ve[i][j] = 70; // For example
val = ve[i][j];
There is no real need to use the wr wrapper macro. Use ve[i][j] and if you have somewhere in your code a std::pair p, use: ve[p.first][p.second] instead of ve[p] - Both are the same. Also, it is nonsense to take (i, j) and to make_pair on-the-fly just to use them again as [i][j] indexes. If, despite all, one insists on the syntax, than use the wr wrapper macro.
--
But, in a case of a fixed sequential range, a 2D std::array is a better choice (& you can add the wrapper macro as well, if you insist):
#include <array>
int main()
{
int i = 7, j = 5;
std::array<std::array<int, 100>, 100> ar; // 100 X 100
ar[0].fill(0); ar.fill(ar[0]); // Initialize to 0
ar[i][j] = 35; // For example
return 0;
}
Are you simply attempting to access 1d vector content as if it was a 2d vector? Perhaps you could use a helper function to convert 2d index into 1d index, for example:
#include <vector>
#include <iostream>
#include <cassert>
template<size_t ROWS, size_t COLS>
size_t convertIndex(size_t row, size_t col)
{
assert(row < ROWS && col < COLS);
return row * COLS + col;
}
int main()
{
std::vector<int> v =
{
0,1,2,3,4,
5,6,7,8,9
};
std::cout << v[convertIndex<2, 5>(1, 3)];
}
This outputs 8
I have a range-image and want to convert it into a libpointmatcher point cloud. The cloud is an Eigen::Matrix with 4 rows (x,y,z,1) and several columns for every point.
The range-image is an unsigned short*array including the range values (z) and an unsigned char*array including information about the pixel visibility.
In serial, my code looks like this:
//container to hold the data
std::vector<Eigen::Vector4d> vec;
vec.reserve(this->Height*this->Width);
//contains information about pixel visibility
unsigned char* mask_data = (unsigned char*)range_image.mask.ToPointer();
//contains the actual pixel data
unsigned short* pixel_data = (unsigned short*)range_image.pixel.ToPointer();
for (int y =0;y < range_image.Height; y++)
{
for (int x = 0; x < range_image.Width; x++)
{
int index =x+y*range_image.Width;
if(*(mask_data+index) != 0)
{
vec.push_back(Eigen::Vector4d(x,y,(double)*(data+index),1));
}
}
}
// libpointmatcher point cloud with size of visible pixel
PM::Matrix features(4,vec.size());
PM::DataPoints::Labels featureLabels;
featureLabels.resize(4);
featureLabels[0] = PM::DataPoints::Label::Label("x");
featureLabels[1] = PM::DataPoints::Label::Label("y");
featureLabels[2] = PM::DataPoints::Label::Label("z");
featureLabels[3] = PM::DataPoints::Label::Label("pad");
//fill with data
for(int i = 0; i<vec.size(); i++)
{
features.col(i) = vec[i];
}
Because of the large images this loop takes 500ms for 840000 points and thats too slow. Now my idea was to integrate the code above in one parallized function. The problem is that the Eigen::Matrix does not provide a push_back functionality, i dont know the number of visible points in advance and i need the points in the right order to process the point cloud.
So i need a parallel algorithm to extract visible 3D-Points from my range-image and insert them into the Eigen::Matrix in the right order. I'm working with Microsoft Visual Studio 2012 and i can use either OpenMP 2.0 or TBB. I appreciate any help :)
UPDATE
As Arch D. Robison suggeested i tried the tbb::parallel_scan. I passed the mask array and a double array to hold the 3D-coodinates. The output array has four times the size of the input array to store homogeneous 3D data (x,y,z,1). Then i map the otput array in a Eigen::Matrix.The number of rows is fixed and the cols coming from the result from the parallel_scan.
size_t vec_size = width*height;
double* out = new double[vec_size * 4];
size_t m1 = Compress(mask, pixel, out, height, width,
[](unsigned char x) {return x != 0; });
Map<MatrixXd> features(out, 4, m1);
. Here is the code from the operator():
void operator()(const tbb::blocked_range2d<size_t, size_t>& r, Tag) {
// Use local variables instead of member fields inside the loop,
// to improve odds that values will be kept in registers.
size_t j = sum;
const unsigned char* m = in;
const unsigned short* p = in2;
T* values = out;
size_t yend = r.rows().end();
for (size_t y = r.rows().begin(); y != yend; ++y)
{
size_t xend = r.cols().end();
for (size_t x = r.cols().begin(); x != xend; ++x)
{
size_t index = x + y*width;
if (pred(m[index]))
{
if (Tag::is_final_scan())
{
size_t idx = j*4;
values[idx] = (double)x;
values[idx + 1] = (double)y;
values[idx + 2] = p[index];
values[idx + 3] = 1.0;
}
++j;
}
}
}
sum = j;
}
I'm now 4x faster then the serial version. What do you think about this approach? Did i miss anythink and are there improvements? Thanks
Here is an example of how to do something like std::copy_if using tbb::parallel_scan. The key method is operator(), which is usually called twice per subrange, once for a prescan and once for a final scan. (But be aware that TBB omits the prescan when it's not necessary.) Here the prescan just does tallying and the final scan does the final work (which includes replaying the tallying). See https://software.intel.com/sites/default/files/bc/2b/parallel_scan.pdf for more details on the methods. Another good references is https://www.cs.cmu.edu/~guyb/papers/Ble93.pdf , which shows lots of things you can do with parallel scan (a.k.a. prefix-sum).
```
#include "tbb/parallel_scan.h"
#include "tbb/blocked_range.h"
#include <cstddef>
template<typename T, typename Pred>
class Body {
const T* const in;
T* const out;
Pred pred;
size_t sum;
public:
Body( T* in_, T* out_, Pred pred_) :
in(in_), out(out_), pred(pred_), sum(0)
{}
size_t getSum() const {return sum;}
template<typename Tag>
void operator()( const tbb::blocked_range<size_t>& r, Tag ) {
// Use local variables instead of member fields inside the loop,
// to improve odds that values will be kept in registers.
size_t j = sum;
const T* x = in;
T* y = out;
for( size_t i=r.begin(); i<r.end(); ++i ) {
if( pred(x[i]) ) {
if( Tag::is_final_scan() )
y[j] = x[i];
++j;
}
}
sum = j;
}
// Splitting constructor used for parallel fork.
// Note that it's sum(0), not sum(b.sum), because this
// constructor will be used to compute a partial sum.
// Method reverse_join will put together the two sub-sums.
Body( Body& b, tbb::split ) :
in(b.in), out(b.out), pred(b.pred), sum(0)
{}
// Join partial solutions computed by two Body objects.
// Arguments "this" and "a" correspond to the splitting
// constructor arguments "b" and "this". That's why
// it's called a reverse join.
void reverse_join( Body& a ) {
sum += a.sum;
}
void assign( Body& b ) {sum=b.sum;}
};
// Copy to out each element of in that satisfies pred.
// Return number of elements copied.
template<typename T, typename Pred>
size_t Compress( T* in, T* out, size_t n, Pred pred ) {
Body<T,Pred> b(in,out,pred);
tbb::parallel_scan(tbb::blocked_range<size_t>(0,n), b);
return b.getSum();
}
#include <cmath>
#include <algorithm>
#include <cassert>
int main() {
const size_t n = 10000000;
float* a = new float[n];
float* b = new float[n];
float* c = new float[n];
for( size_t i=0; i<n; ++i )
a[i] = std::cos(float(i));
size_t m1 = Compress(a, b, n, [](float x) {return x<0;});
size_t m2 = std::copy_if(a, a+n, c, [](float x) {return x<0;})-c;
assert(m1==m2);
for( size_t i=0; i<n; ++i )
assert(b[i]==c[i]);
}
```
Why do not you check out the condition *(m_maskData+index)==0 before m_features(0,index) = x;?
I already know how to create a dynamic 2D matrix using new and free it using delete. Since C++ 11 is here with many new memory features such as unique_ptr, array container etc.; what is a nice way to create a 2D matrix so that one needs not to free the matrix explicitly using delete operator?
One of the simplest ways is to use a vector of vectors
const int N = 10;
const int M = 10;
vector<vector<int>> matrix2d(N, vector<int>(M, 0)); // 10x10 zero-initialized matrix
matrix2d[0][0] = 42;
You could of course use a single vector and wrap it into an accessor class
vector<int> matrix(N * M, 0) // Ditto as above, but needs stride-aware accessors
I'll post a small example here for completeness' sake
template <typename T>
class Matrix2D {
std::vector<T> data;
unsigned int sizeX, sizeY;
public:
Matrix2D (unsigned int x, unsigned int y)
: sizeX (x), sizeY (y) {
data.resize (sizeX*sizeY);
}
T& operator()(unsigned int x, unsigned int y) {
if (x >= sizeX || y>= sizeY)
throw std::out_of_range("OOB access"); // Throw something more appropriate
return data[sizeX*y + x]; // Stride-aware access
}
};
Live Example
or perhaps combine your way with a smart pointer. Notice that the vector<vector<int>> approach should be used with caution since the vectors are independent from each other and there's nothing to enforce that they should keep their size fixed.
I strongly suggest using array_view from the GSL, which will eventually be part of the standard.
#include <array>
#include <vector>
#include "array_view.h" // must be manually imported until standardization
int main()
{
std::array<int, 10> arr{}; // 10 ints on the stack
std::vector<int> vec{12}; // 12 ints on the heap
auto a = gsl::array_view<int, 2>{{2, 5}, arr}; // 2D, 2x5 matrix
auto b = gsl::array_view<int, 3>{{3, 2, 2}, vec}; // 3D, 3x2x2 matrix
auto c = gsl::array_view<int>{vec}; // 1D, spans from `begin()` to `end()`
a[{0,3}] += b[{0,1,1}] * -c[2]; // access syntax
}
N.B. array_view holds no control over the lifetime of the range it looks at. See here for full details.
Edit:
array_view is dead as it was becoming too complicated in handling multidimensional arrays with zero cost abstraction. You should instead use span from the GSL.
See this for more information about span.
Based on above answers, I have found a simple way to create matrices although not using C++11 features. Here is an illustration.
#include <iostream>
#include <vector>
using namespace std;
typedef vector<vector<int>> Matrix2D;
typedef vector<Matrix2D> Matrix3D;
Matrix2D my_arr;
int main()
{
const size_t N = 9;
for(unsigned s = 4; s <= N; s++)
{
my_arr.resize(s);
for(unsigned i = 0; i < s; i++)
my_arr[i].resize(s,s);
for(unsigned i = 0; i < s; i++)
{
for(unsigned j = 0; j < s; j++)
cout << my_arr[i][j] << " ";
cout << endl;
}
cout << "\n\n";
}
return 0;
}
I need to write a program that computes values in a matrix, first sequentially, then in parallel using openCL.
It is the same thing as I already did in regular C (using MPI)
I want to make simple functions to initializeMatrix and printMatrix and the likes.
In C i used to do this very simply :
// Matrix initialization
void initMatrix(size_t M, size_t N, double (*matrix)[M][N][2])
{
int i, j;
for (j = 0; j < N; ++j)
{
for (i = 0; i < M; ++i)
{
(*matrix)[i][j][0] = (double)(( i * ( M - i - 1 ) ) * ( j * ( N - j - 1 ) ));
(*matrix)[i][j][1] = (*matrix)[i][j][0];
}
}
printf("Matrix has been initialized\n");
}
I saw this gets me errors in C++, as the compiler wants to know at COMPILE TIME the sizes of arrays (the M and N sizes are passed as arguments to program, therefore I can't know at compile time).
How do I do this in C++?
I am considering using Vectors, but I'm not sure if it's a good idea since I will have to use the OpenCL library
You can pass the array by reference/const reference via a template:
#include <iostream>
#include <cstddef> // for std::size_t
template <typename T, int M, int N, int P>
void f(T (&arr)[M][N][P]) // accepts 3-D arrays of arbitrary types
{
std::cout << "Size: " << M << " x " << N << " x " << P;
}
int main()
{
const std::size_t M = 2;
const std::size_t N = 3;
double arr[M][N][4];
f(arr);
}