C++ Data Structure to Find Neighbouring Values in Multidimensional Array - c++

I have a project where I read in an array that has 1 or more dimensions, and for this project I need to be able to determine a given element's neighbours quickly. I do not know the dimensionality ahead of time, and I likewise do not know the size of the dimensions ahead of time. What would be the best C++ data structure to store this data in? A colleague recommended a vector of vectors of vectors of . . ., but that seems incredibly unwieldy.

If you know the address of which element you need the neighbors for, could you just do pointer arithmetic to find out the neighbors. For example, if p is the location of the element, then p-- is the left neighbor and p++ is the right neighbor.

Think your multidimensional array as a 1D array. Let the dimension of the array is d1 * d2 * ....* dn
Then allocate memory for a 1D array, say A of size d1 * d2 * ....* dn. For example,
int *A = new int[d1 * d2 * ....* dn];
If you need to store data in the [i1][i2]...[in] th index, then store in the following index:
A[i1 * (d2*d3*d4.. *dn) + i2 * (d3*d4*....dn) + ..... + in]
Neighboring elements will be:
A[(i1 + 1) * (d2*d3*d4.. *dn) + i2 * (d3*d4*....dn) + ..... + in]
A[(i1 - 1) * (d2*d3*d4.. *dn) + i2 * (d3*d4*....dn) + ..... + in]
A[i1 * (d2*d3*d4.. *dn) + (i2 + 1) * (d3*d4*....dn) + ..... + in]
A[i1 * (d2*d3*d4.. *dn) + (i2 - 1) * (d3*d4*....dn) + ..... + in]
.............................
A[i1 * (d2*d3*d4.. *dn) + i2 * (d3*d4*....dn) + ..... + (in + 1)]
A[i1 * (d2*d3*d4.. *dn) + i2 * (d3*d4*....dn) + ..... + (in - 1)]

Related

Eigen - reshape a vector to matrix

I am trying to reshape a vector to a matrix, but getting the following error
unsigned int Nx = 8;
unsigned int Ny = 7;
Eigen::VectorXi G_temp = Eigen::VectorXi::LinSpaced((Nx + 2) * (Ny + 2),0,(Nx + 2) * (Ny + 2)-1);
Eigen::MatrixXd G = Eigen::Map<Eigen::MatrixXd>(G_temp.data(),Nx+2, Ny+2); // error: no matching constructor for initialization of 'Eigen::Map<Eigen::MatrixXd>'
I followed what is written here, but I do not understand the way I am doing wrong.
There is no implicit conversion from integer-valued to double-valued expressions in Eigen. Either just use VectorXd for G_temp (and the LinSpaced expression):
Eigen::VectorXd G_temp = Eigen::VectorXd::LinSpaced((Nx + 2) * (Ny + 2),0,(Nx + 2) * (Ny + 2)-1);
Or use a MatrixXi-Map and .cast<double>() the result before assigning it to G.
Eigen::MatrixXd G = Eigen::Map<Eigen::MatrixXi>(G_temp.data(),Nx+2, Ny+2).cast<double>();
To avoid any temporary, you can also allocate a MatrixXd and directly assign the proper values inside:
Eigen::MatrixXd G(Nx+2, Ny+2); // allocate matrix
// set values in-place:
Eigen::VectorXd::Map(G.data(), (Nx + 2) * (Ny + 2)).setLinSpaced(0,(Nx + 2) * (Ny + 2)-1);
Or with the master/3.4 branch:
G.reshaped().setLinSpaced(0,(Nx + 2) * (Ny + 2)-1);

How to calculate where an indexed value in a 3d array will be in memory? How to calculate where an indexed value in a char** will be in memory?

The problem states: Given the following array declarations and indexed accesses, compute the address where the indexed value will be in memory. Assume the array starts at location 200 on a 64-bit computer.
a. double d[3][4][4]; d[1][2][3] is at: _________
b. char *n[10]; n[3] is at: _________
I know the answers are 416 and 224 (respectively), but I do not understand how those numbers were reached.
For part a, I was told the equation:
address-in-3d-array= start-address + (p * numR * numC + (i * numC) + j) * size-of-type
(where start address = 200, the numR and numC come from the original array, and the i,j, and p come from the location you are trying to find).
Nothing I do makes this equation come to 416. I have been viewing the order of the array as d[row][column][plane]. Is that incorrect? I have also tried looking at it as d[plane][row][column], but that didn't seem to work either.
For part b, I'm not sure where to start as I thought that as the array is an array of pointers, it's location would be in the heap. I'm not sure how to get 224 from that.
I need to answer these questions by hand, not using code.
For this array declaration
double d[3][4][4];
to calculate the address of the expression
d[1][2][3]
You can use the following formula
reinterpret_cast<double *>( d ) + 1 * 16 + 2 * 4 + 3
that is the same (relative to the value of the expression) as
reinterpret_cast<char *>( d ) + 27 * sizeof( double )
So you can calculate the address like the address of the first element of the array plus the expression 27 * sizeof( double ) where double is equal to 8.
For this array
char *n[10];
the address of the expression
n[3]
is
reinterpret_cast<char *>( n ) + 3 * sizeof( char * )
In words:
Given a generic array d[s1][s2][s3] of elements of size S, the offset of the d[x][y][z] element is
[(x * s2 * s3) + (y * s3) + z] * S
In the array double d[3][4][4], with S = sizeof(double) = 8, the location of d[1][2][3] is at offset:
[(1 * 4 * 4) + (2 * 4) + 3] * 8 = 216
Sum the offset (216) to the start (200) to get 416.
Given a generic array n[s1] of elements of size S, the offset of the n[x] element is
x * S
In the array char * n[10], with S = 8 (pointers size on 64bit platforms), the location of n[3] is at offset
3 * 8 = 24
Sum the offset (24) to the start (200) to get 224.
In code:
int main()
{
double d[3][4][4];
size_t start = 200;
size_t offset =
sizeof(d[0]) * 1
+ sizeof(d[0][0]) * 2
+ sizeof(d[0][0][0]) * 3;
std::cout << start + offset << std::endl; //416 on my machine
char * n[10];
offset = 3 * sizeof(char*);
std::cout << start + offset << std::endl; //224 on every 64bit platforms
}

How to handle the indices of a 9-dimensional matrix

I am a physicist currently writing a C++ program dealing with multidimensional integration; in particular, the functions I am considering can have up to D=9 dimensions.
From a mathematical perspective, I need to handle a NxNxN...xN (D times) matrix, but from a programming point of view, I was instructed to use an array of NxNxN...xN elements instead. From what I know, an array is better for the sake of generality and for all the ensuing calculations involving pointers.
However, now I am stuck with a problem I cannot solve.
I need to perform some calculations where a single index of my matrix is fixed and all the other ones take all their different values.
If it were a 3x3x3 matrix, the code would be something similar to the following:
double test[3][3][3];
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
test[0][i][j]=i*j;
}
}
i.e. I could have an index fixed and cycle through the other ones.
The same process could be extended to the second and the third index as well.
How can I accomplish the same effect with a double test[3*3*3]? Please keep in mind that the three dimensional matrix is just an example; the real matrices I am dealing with are 9-dimensional, and so I need a general way to keep a single index of my matrix fixed and cycle through all the other ones.
TL;DR: I have an array which represents a NxNxN...xN (9 times) matrix.
I need to perform some calculations on the array as if a single index of my matrix were fixed and all the other ones were cycling through all their possible values.
I know there is a simple expression for the case where a 2-D matrix is mapped in a 1-D array; does something similar exist here?
Raster scan is the standard way of ordering elements for two dimensions.
If you have a 2-D array test[3][3], and you access it by test[i][j], the corresponding one-dimensional array would be
double raster[3 * 3];
and you would access it as follows:
raster[i * 3 + j];
This can be generalized to 3 dimensions:
double raster[3 * 3 * 3];
...
raster[a * 9 + b * 3 + c];
Or to 9 dimensions:
double raster[3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3];
...
raster[a * 6561 + b * 2187 + c * 729 + d * 243 + e * 81 + f * 27 + g * 9 + h * 3 + i];
Having any of the a ... i index variables constant, and changing the rest in a loop, will access a 8-D slice in your 9-D array.
You might want to define some struct to hold all these indices, for example:
struct Pos
{
int a, b, c, d, e, f, g, h, i;
};
Then you can convert a position to a 1-D index easily:
int index(Pos p)
{
return p.a * 6561 + p.b * 2187 + p.c * 729 + p.d * 243 + p.e * 81 + p.f * 27 + p.g * 9 + p.h * 3 + p.i;
}
Generally, a flattened array will contain its elements in the following way: the elements of the last dimension will be mapped into repeated groups, the inner-most groups will be the second dimension from the back and so on:
values[x][y][z] => { x0 = { y0_0 = { z0_0_0, z0_0_1, ..., z0_0_N }, y0_1 = { z0_1_0, z0_1_1, ... }, ... y0_N }, x1 = ... }
values[x*y*z] => { z0_0_0, z0_0_1, ..., z0_0_N, z0_1_0, z0_0_1, ... }
I hope this makes sense outside my brain.
So, any element access will need to calculate, how many blocks of elements come before it:
Accessing [2][1][3] means, skip 2 blocks of x, each containing y blocks with z elements, then skip another 1 block of y containing z elements and access the 3rd element from the next block:
values[2 * y * z + 1 * z + 3];
So more generally for N dimensions d1, d2, d3 .. dn, and an n-dimensional index i1, i2, .. iN to be accessed:
[i1 * d2 * ... * dN + i2 * d3 * ... * dN + ... + iN]
Back to your example:
double test[3*3*3];
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
// test[0*3*3 + i*3 + j] = i * j;
test[i*3 + j] = i * j;
}
}
If the matrix has the same size for all dimensions, then you can access them like this:
m[x + y*N + z*N*N + w*N*N*N ...]
In the case that the sizes are different, it is a little bit more complicated:
m[x + y*N1 + z*N1*N2 + w*N1*N2*N3 ...]

SIMD/SSE : short dot product and short max value

I'm trying to optimize a dot product of two c-style arrays of contant and small size and of type short.
I've read several documentations about SIMD intrinsics and many blog posts/articles about dot product optimization using this intrisincs.
However, i don't understand how a dot product on short arrays using this intrinsics can give the right result. When making the dot product, the computed values can be (and are always, in my case) greater than SHORT_MAX, so is there sum. Hence, i store them in a variable of double type.
As i understand the dot product using simd intrinsic, we use __m128i variables types and operations are returning __m128i. So, what i don't understand is why it doesn't "overflow" and how the result can be transformed into a value type that can handle it?
thanks for your advices
Depending on the range of your data values you might use an intrinsic such as _mm_madd_epi16, which performs multiply/add on 16 bit data and generates 32 bit terms. You would then need to periodically accumulate your 32 bit terms to 64 bits. How often you need to do this depends on the range of your input data, e.g. if it's 12 bit greyscale image data then you can do 64 iterations at 8 elements per iteration (i.e. 512 input points) before there is the potential for overflow. In the worst case however, if your input data uses the full 16 bit range, then you would need to do the additional 64 bit accumulate on every iteration (i.e. every 8 points).
Just for the records, here is how i make an dot product for 2 int16 arrays of size 36:
double dotprod(const int16_t* source, const int16_t* target, const int size){
#ifdef USE_SSE
int res[4];
__m128i* src = (__m128i *) source;
__m128i* t = (__m128i *) target;
__m128i s = _mm_madd_epi16(_mm_loadu_si128(src), mm_loadu_si128(t));
++src;
++t;
s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));
++src;
++t;
s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));
++src;
++t;
s = _mm_add_epi32(s, _mm_madd_epi16(_mm_loadu_si128(src), _mm_loadu_si128(t)));
/* return the sum of the four 32-bit sub sums */
_mm_storeu_si128((__m128i*)&res, s);
return res[0] + res[1] + res[2] + res[3] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#elif USE_AVX
int res[8];
__m256i* src = (__m256i *) source;
__m256i* t = (__m256i *) target;
__m256i s = _mm256_madd_epi16(_mm256_loadu_si256(src), _mm256_loadu_si256(t));
++src;
++t;
s = _mm256_add_epi32(s, _mm256_madd_epi16(_mm256_loadu_si256(src), _mm256_loadu_si256(t)));
/* return the sum of the 8 32-bit sub sums */
_mm256_storeu_si256((__m256i*)&res, s);
return res[0] + res[1] + res[2] + res[3] + res[4] + res[5] + res[6] + res[7] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#else
return source[0] * target[0] + source[1] * target[1] + source[2] * target[2] + source[3] * target[3] + source[4] * target[4]+ source[5] * target[5] + source[6] * target[6] + source[7] * target[7] + source[8] * target[8] + source[9] * target[9] + source[10] * target[10] + source[11] * target[11] + source[12] * target[12] + source[13] * target[13] + source[14] * target[14] + source[15] * target[15] + source[16] * target[16] + source[17] * target[17] + source[18] * target[18] + source[19] * target[19] + source[20] * target[20] + source[21] * target[21] + source[22] * target[22] + source[23] * target[23] + source[24] * target[24] + source[25] * target[25] + source[26] * target[26] + source[27] * target[27] + source[28] * target[28] + source[29] * target[29] + source[30] * target[30] + source[31] * target[31] + source[32] * target[32] + source[33] * target[33] + source[34] * target[34] + source[35] * target[35];
#endif
}

How to ccDrawPoly and fill?

- (void)draw {
lines[0] = ccp(self.l.x + (segmentIndex[0] * segmentSpacing), self.l.y);
lines[1] = ccp(self.l.x + (segmentIndex[1] * segmentSpacing), self.l.y + segmentHeight * 1);
lines[2] = ccp(self.l.x + (segmentIndex[2] * segmentSpacing), self.l.y + segmentHeight * 2);
lines[3] = ccp(self.l.x + (segmentIndex[3] * segmentSpacing), self.l.y + segmentHeight * 3);
lines[4] = ccp(lines[3].x + segmentWidth, lines[3].y);
lines[5] = ccp(lines[2].x + segmentWidth, lines[2].y);
lines[6] = ccp(lines[1].x + segmentWidth, lines[1].y);
lines[7] = ccp(lines[0].x + segmentWidth, lines[0].y);
ccDrawPoly(lines, 8, YES);
//ccDrawSolidPoly(lines, 8, [self color]);
}
The ccDrawPoly line draws the zig-zag style shape I intend to draw.
There are 4 Y segments and each one has a point determined by segmentIndex & segmentSpacing, then +segmentWidth on the x for a total of 8 points.
I go down the left-most points first, then walk my way back up.
When I call ccDrawSolidPoly, it fills in the shape in a different way. It fills in a polygon using all the outermost points instead of drawing lines in the order I set in points.
How do I do ccDrawPoly and fill?
Write my own function, apparently.
Forum results showed people editing the cocos2d ccDrawSolidPoly function.