Change to n dimensions at run-time - c++

I have a simple C++ code as below. I need to do a specific task for n dimensions. But the value of n i will get only during runt-time. How can i adpat the code to n dimesnions with vectors at run-time.
//one dimesion
std::vector<int> a;
// do some task with a;
// two dimension
std::vector< std::vector<int> > a;
// do some task with a;
.
.
Thanks

You can implement an n-dimensional array using a single vector.
This works like this:
Say your array(A[s1]) is one dimensional. Then array element is accessed like A[i1].
If your array is two dimensional(A[s1][s2]), elements A[0][0] to A[0][s2-1] are stored first and then A[1][0] to A[1][s2-1] follows. Note that all elements are stored in sequentially in single vector. So array element is accessed like A[ i1*s2 + i2 ].
For three dimensional array A[s1][s2][s3], you can think of it as s1-number of two dimensional arrays. the two-dimensional array at A[0] is stored first, then next two dimensional array at A[1] is stored and so on. So element can be accessed using A[ i1*s2*s3 + i2*s3 + i3].
An array with 'n' dimensions, can have its element accessed at [i1][i2][i3]...[in] as:
my_vector[ i1*(s2*s3*...*sn) + i2*(s3*s4*...*sn) + i3*(s4*...*sn) + ... + in ]
where s1, s2, s3, ..., sn are sizes of 1st, 2nd, ..., n-th dimension respectively.

If you want to define a generic algorithm on multidimensional vectors without knowing their dimension (see comments to the question), youd could proceed with a recursive template as in the following simple example:
template <typename T>
void myalgo(T v) // generic algorithm
{
myalgo_imp(v, static_cast<T*>(0)); // trick to distinguish vectors from non vectors
}
template <typename T>
void myalgo_imp(vector<T> cplx, vector<T> *) // vector implementation
{
for (T x : cplx) // Reaply the generic algorithm to the dimension less 1
myalgo (x);
}
template <typename T >
void myalgo_imp(T base, T*) // Apply the generic algorithm for base class (non vector)
{
cout << base << endl;
}
The trick with the static cast is explained in this SO question:
You could then use the algorithm as you've requested:
//one dimesion
std::vector<int> a(3);
myalgo(a);
// two dimension
std::vector< std::vector<int> > aa(3, vector<int>(2,1));
myalgo(aa);
This example is suitable, for example if you want to perform a base task on every base element of your multidimensional vector. Not knowing how your algorithm processes the vector, it's difficult to give a more tailored adaptation of this technique.

Related

C++ variable to hold any dimensional array

Is it possible in c++ to create a type of variable that can hold an array with any dimensions? I mean a variable that can store a 1, 2, 3 ... dimensional array.
I guess that it can be made by templates but I could not figure it out how. I would really appreciate if anyone could help.
It sounds like you want to "create a function that can multiply arrays" that will be used "for a lot of different dimensions."
I would deal with this just like I would deal with a vector output operator: use templates with recursion!
If I wanted to make a function to sum all of the numbers in two vector's when I add them, I could do:
template <typename T>
int operator+(std::vector<T> v1, std::vector<T> v2) {
if(v1.size() != v2.size()) { throw; } //for simplicity
int sum = 0;
for(size_t x = 0; x < v1.size(); x++) {
sum += v1.at(x) + v2.at(x);
}
return sum;
}
Note that the magic here is in the line
sum += v1.at(x) + v2.at(x);
If v1.at(x) and v2.at(x) are std::vector's, we'll just recursively call this function again. But if they're int's, we'll add them into sum and move on.
You can see this in action here: ideone
You could do something similar for your array multiplication. Break the problem down into smaller pieces so you can use recursion and let the templates handle the rest!
Do you ever try dynamic memory? In the case below, it creates a two-dimensional array.
http://www.cplusplus.com/doc/tutorial/dynamic/
If you want to have a three-dimensional array, maybe you can try to define a two-dimensional array in step two of the above example.
For four-dimensional array, third-dimensional array in step 2.
Or, you can keep using pointer.

C++ N nested vectors at runtime

In C++ (with or without boost), how can I create an N dimensional vectors where N is determined at runtime?
Something along the lines of:
PROCEDURE buildNVectors(int n)
std::vector < n dimensional std::vector > *structure = new std::vector< n dimensional std::vector >()
END
If passed 1, a vector would be allocated. If passed 2, a 2d nested matrix would be allocated. If passed 3, a 3d cube is allocated. etc.
Unfortunately you will not be able to do this. A std::vector is a template type and as such it's type must be known at compile time. Since it's type is used to determine what dimensions it has you can only set that at compile time.
The good news is you can make your own class that uses a single dimension vector as the data storage and then you can fake that it has extra dimensions using math. This does make it tricky to access the vector though. Since you will not know how many dimensions the vector has you need to have a way to index into the container with an arbitrary number of elements. What you could do is overload the function call operator operator with a std::intializer_list which would allow you to index into it with something like
my_fancy_dynamic_dimension_vector({x,y,z,a,b,c});
A real rough sketch of what you could have would be
class dynmic_vector
{
std::vector<int> data;
int multiply(std::initializer_list<int> dims)
{
int sum = 1;
for (auto e : dims)
sum *= e;
return sum;
}
public:
dynmic_vector(std::initializer_list<int> dims) : data(multiply(dims)) {}
int & operator()(std::initializer_list<int> indexs)
{
// code here to translate the values in indexes into a 1d position
}
};
Or better yet, just use a boost::multi_array

getting certain component of all elements in vector

I have stored some elements of a struct, let's call it myStruct, in a vector.
Now I want to get a certain component of this struct of all the elements in my vector.
Is there a possibility to do this fast, without using a for-loop? Is there an equivalent solution for deque?
struct myStruct{
int a;
int b;
};
vector<myStruct> vec;
//creating some data and push back to vector
myStruct ms0,ms1;
ms0.a = 5;
ms1.a = 10;
vec.push_back(ms0);
vec.push_back(ms1);
//now I want to get the component a of ms0 and ms1
You could use two vectors, one storing component a, one storing component b, instead of one vector storing pairs (a, b).
If this doesn't work for you, you can do something like (this is C++11 or higher):
std::for_each(vec.begin(), vec.end(),
[] (myStruct &v) {std::cout << v.a << '\n';} );
But this is not (in terms of complexity) better than a for loop.
Vectors are sequence containers, more specifically arrays that can change their size dynamically, thus to access all of their elements it will take time proportional to their size, n. Thus the answer to your first question:
Is there a possibility to do this fast, without using a for-loop?
is: No
As for the second question:
Is there an equivalent solution for deque?
Yes, there is and it will look the same as the one posted, with the small difference in the container which instead of vector<myStruct> vec; will be std::deque<int> mydeque;
Internally vector uses arrays so you can directly access its elements using [] operator,
eg:
cout<< vec[0].a << vec[1].a;

Making only the outer vector in vector<vector<int>> fixed

I want to create a vector<vector<int>> where the outer vector is fixed (always containing the same vectors), but the inner vectors can be changed. For example:
int n = 2; //decided at runtime
assert(n>0);
vector<vector<int>> outer(n); //outer vector contains n empty vectors
outer.push_back(vector<int>()); //modifying outer vector - this should be error
auto outer_it = outer.begin();
(*outer_it).push_back(3); //modifying inner vector. should work (which it does).
I tried doing simply const vector<vector<int>>, but that makes even the inner vectors const.
Is my only option to create my own custom FixedVectors class, or are there better ways out there to do this?
by definition,
Vectors are sequence containers representing arrays that can change in
size. Just like arrays, vectors use contiguous storage locations for
their elements, which means that their elements can also be accessed
using offsets on regular pointers to its elements, and just as
efficiently as in arrays. But unlike arrays, their size can change
dynamically, with their storage being handled automatically by the
container.
if you aren't looking to have a data structure that changes in size, a vector probably isn't the best choice for an outer layer, How about using an array of vectors. This way the array is of a fixed size and cannot be modified, while still having the freedom of having its size declared in runtime.
vector<int> *outer;
int VectSize;
cout >> "size of vector array?"
cin >> VectSize;
outer = new vector<int>[VectSize]; //array created with fixed size
outer.push_back() //not happening
Wrap the outer vector into a class which just provides at, begin, end and operator []. Let the class take only have one constructor taking its capacity.
This most probably the best way.
const vector<unique_ptr<vector<int>>> outer = something(n);
For the something, you might write a function, like this:
vector<unique_ptr<vector<int>>> something(int n)
{
vector<unique_ptr<vector<int>>> v(n);
for (auto & p : v)
p.reset(new vector<int>);
return v;
}

std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless.
Suppose I wish to create a vector of a multidimensional, static array. Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5].
Can I be certain that all N*5 integers are now contiguous in memory? So that I in principle could access all of the integers simply by knowing the address of the first element? Is this implementation dependent?
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
The standard does require the memory of an std::vector to be
contiguous. On the other hand, if you write something like:
std::vector<std::vector<double> > v;
the global memory (all of the v[i][j]) will not be contiguous. The
usual way of creating 2D arrays is to use a single
std::vector<double> v;
and calculate the indexes, exactly as you suggest doing with float.
(You can also create a second std::vector<float*> with the addresses
if you want. I've always just recalculated the indexes, however.)
Elements of a Vector are gauranteed to be contiguous as per C++ standard.
Quotes from the standard are as follows:
From n2798 (draft of C++0x):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
C++03 standard (23.2.4.1):
The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Also, see here what Herb Sutter's views on the same.
As #Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. I would not, however, simulate a 2D matrix with an array of pointers. Instead, I'd recommend one of two approaches. The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector:
template <class T>
class matrix2D {
std::vector<T> data;
int columns;
public:
T &operator()(int x, int y) {
return data[y * columns + x];
}
matrix2D(int x, int y) : data(x*y), columns(x) {}
};
If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer.
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
That's not a 2D array, that's an array of pointers. If you want a real 2D array, this is how it's done:
float (*p)[5] = new float[N][5];
p [0] [0] = 42; // access first element
p[N-1][4] = 42; // access last element
delete[] p;
Note there is only a single allocation. May I suggest reading more about using arrays in C++?
Under the hood, a vector may look approximately like (p-code):
class vector<T> {
T *data;
size_t s;
};
Now if you make a vector<vector<T> >, there will be a layout like this
vector<vector<T>> --> data {
vector<T>,
vector<T>,
vector<T>
};
or in "inlined" form
vector<vector<T>> --> data {
{data0, s0},
{data1, s1},
{data2, s2}
};
Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. It most probably stores an array of pointers (and some other variables) to external places.
The standard only requires that the data of a vector is contiguous, but not the vector as a whole.
A simple class to create, as you call it, a 2D array, would be something like:
template <class T> 2DArray {
private:
T *m_data;
int m_stride;
public:
2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
~2DArray() { delete[] m_data; }
T* operator[](int row) { return m_data + m_stride * row; }
}
It's possible to use this like:
2DArray<int> myArray(30,20);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 20; j++)
myArray[i][j] = i + j;
Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers".
But as you see, it turns naive expectations around in that it's myarray[y][x].
Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ?
Edit: As said, the above is simple. No bounds check attempts whatsoever. Just like, "an array".