linear simulation of multidimensional array - arrays

I know how to simulate a 2d array in a linear array using [x + y * width] as a linear index.
I can extend this to 3d arrays: [x + y * width + z * width * height].
Is there a general formula for N-dimensional array?
I'm looking for a language-agnostic answer.

Sure. Just extending your example gives x + y*width + z*width*height + w*width*height*depth + ...
In other words, dim1 + dim2*size1 + dim3*size1*size2 + dim4*size1*size2*size3 + ...

Eh, if you want some code... :-) C is language-agnostic enough, ya?
Assume input: location[dimensions]
Assume a table exists maxBound[dimensions] that contains the maximum boundaries of each dimension of the table.
int index = 0;
int multiplier = 1;
for (int i = 0;i < dimensions;i++)
{
index += location[i] * multiplier;
multiplier *= maxBound[i];
}
Your index will end up in the index field.
Test:
location = [3,4,5]
maxBound = [10,20,30]
loop initial: index = 0, multiplier = 1.
loop i=0: index = 3, multiplier = 10.
loop i=1: index = 43, multiplier = 200.
loop i=2: index = 1043, multipler = 6000.
I think this makes sense, but this is just coming out of the top of my head.

Related

How to navigate a 1d array in a 2d manner?

I've got this sample code below. I understand cells is being made in a 1 dimensional manner,
since the compiler stores 2d arrays in memory row-by-row in 1d. What I don't understand/can't visualize is how to access elements or change positions.
I know board->cells[i + (20 * (10 - 1))] = FLAG_WALL; is used to set flags for the bottom most row. From the format it looks to be using a formula but I am unsure of what it is. The formula also seems to change for the right and left edges.
(board->cells[i * 20 + 20 - 1] = FLAG_WALL;)
Looking at the line board->cells[20 * 2 + 2] = FLAG_SNAKE; it seems cell[42] is where the snake flag is spawned. What would the arithmetic look like to shift its position by 1 cell up, down, right, left? When imagining cell[42] as a part of a 1d array in memory I can't figure out the arithmetic nor the resulting cell number after a shift such as 'up'.
board_init_status_t initialize_default_board(board_t* board) {
board->width = 20;
board->height = 10;
board->cells = calloc(20 * 10, sizeof(int));
// Set edge cells!
// Top and bottom edges:
for (int i = 0; i < 20; ++i) {
board->cells[i] = FLAG_WALL;
board->cells[i + (20 * (10 - 1))] = FLAG_WALL;
}
// Left and right edges:
for (int i = 0; i < 10; ++i) {
board->cells[i * 20] = FLAG_WALL;
board->cells[i * 20 + 20 - 1] = FLAG_WALL;
}
// Add snake
board->cells[20 * 2 + 2] = FLAG_SNAKE;
return INIT_SUCCESS;
}
Think of the 1d array as a 2d one, the beginning of the last row would be at the position width * (height - 1) and the last cell of the last row at width * height almost the same logic goes for the sides.
board->cells[20 * 2 + 2] = FLAG_SNAKE; means it goes at the 2nd row in position 2. Or in (x;y) coordinates (2, 2). It's pure math. If you want to move in a 1d array like in a 2d one just multiply the length of one line by the index of the row you want to go (let's call it y) and then add x to reach the x cell.
board_init_status_t initialize_default_board(board_t* board) {
board->width = 20;
board->height = 10;
board->cells = calloc(20 * 10, sizeof(int));
// Set edge cells!
// Top and bottom edges:
for (int i = 0; i < 20; ++i) {
board->cells[i] = FLAG_WALL; // [0, 19] (top row)
board->cells[i + (20 * (10 - 1))] = FLAG_WALL; // [180, 199] (bottom row)
}
// Left and right edges:
for (int i = 0; i < 10; ++i) {
board->cells[i * 20] = FLAG_WALL; // (left row)
board->cells[i * 20 + 20 - 1] = FLAG_WALL; // (right row)
}
// Add snake
board->cells[20 * 2 + 2] = FLAG_SNAKE;
return INIT_SUCCESS;
}

Xor of all pairwise sums of integers in an array

We have an array A for example [1, 2, 3]. I want to find the XOR of the SUM of all pairs of integers in the array.
Though this can easily be done in O(n^2) (where n is the size of the array) by passing over all of the pairs, I want to improve the time complexity of the solution? Any answer that improves the time complexity would be great.
E.g. for the above example array, A, the answer would be (1+2)^(1+3)^(2+3) = 2. Since the pairwise elements are (1,2), (1,3), (2,3), and 3 ^ 4 ^ 5 = 2.
Here's an idea for a solution in O(nw) time, where w is the size of a machine word (generally 64 or some other constant). The most important thing is counting how many of the pairs will have a particular bit set, and the parity of this number determines whether that bit will be set in the result. The goal is to count that in O(n) time instead of O(n2).
Finding the right-most bit of the result is easiest. Count how many of the input numbers have a 0 in the right-most place (i.e. how many are even), and how many have a 1 there (i.e. how many are odd). The number of pairs whose sum has a 1 in the rightmost place equals the product of those two counts, since a pair must have one odd and one even number for its sum to be odd. The result has a 1 in the rightmost position if and only if this product is odd.
Finding the second-right-most bit of the result is a bit harder. We can do the same trick of counting how many elements do and don't have a 1 there, then taking the product of those counts; but we also need to count how many 1 bits are carried into the second place from sums where both numbers had a 1 in the first place. Fortunately, we can compute this using the count from the previous stage; it is the number of pairs given by the formula k*(k-1)/2 where k is the count of those with a 1 bit in the previous place. This can be added to the product in this stage to determine how many 1 bits there are in the second place.
Each stage takes O(n) time to count the elements with a 0 or 1 bit in the appropriate place. By repeating this process w times, we can compute all w bits of the result in O(nw) time. I will leave the actual implementation of this to you.
Here's my understanding of at least one author's intention for an O(n * log n * w) solution, where w is the number of bits in the largest sum.
The idea is to examine the contribution of each bit one a time. Since we are only interested in whether the kth bit in the sums is set in any one iteration, we can remove all parts of the numbers that include higher bits, taking them each modulo 2^(k + 1).
Now the sums that would necessarily have the kth bit set lie in the intervals, [2^k, 2^(k + 1)) and [2^(k+1) + 2^k, 2^(k+2) − 2]. So we sort the input list (modulo 2^(k + 1)), and for each left summand, we decrement a pointer to the end of each of the two intervals, and binary search the relevant start index.
Here's JavaScript code with a random comparison to brute force to show that it works (easily translatable to C or Python):
// https://stackoverflow.com/q/64082509
// Returns the lowest index of a value
// greater than or equal to the target
function lowerIdx(a, val, left, right){
if (left >= right)
return left;
mid = left + ((right - left) >> 1);
if (a[mid] < val)
return lowerIdx(a, val, mid+1, right);
else
return lowerIdx(a, val, left, mid);
}
function bruteForce(A){
let answer = 0;
for (let i=1; i<A.length; i++)
for (let j=0; j<i; j++)
answer ^= A[i] + A[j];
return answer;
}
function f(A, W){
const n = A.length;
const _A = new Array(n);
let result = 0;
for (let k=0; k<W; k++){
for (let i=0; i<n; i++)
_A[i] = A[i] % (1 << (k + 1));
_A.sort((a, b) => a - b);
let pairs_with_kth_bit = 0;
let l1 = 1 << k;
let r1 = 1 << (k + 1);
let l2 = (1 << (k + 1)) + (1 << k);
let r2 = (1 << (k + 2)) - 2;
let ptr1 = n - 1;
let ptr2 = n - 1;
for (let i=0; i<n-1; i++){
// Interval [2^k, 2^(k+1))
while (ptr1 > i+1 && _A[i] + _A[ptr1] >= r1)
ptr1 -= 1;
const idx1 = lowerIdx(_A, l1-_A[i], i+1, ptr1);
let sum = _A[i] + _A[idx1];
if (sum >= l1 && sum < r1)
pairs_with_kth_bit += ptr1 - idx1 + 1;
// Interval [2^(k+1)+2^k, 2^(k+2)−2]
while (ptr2 > i+1 && _A[i] + _A[ptr2] > r2)
ptr2 -= 1;
const idx2 = lowerIdx(_A, l2-_A[i], i+1, ptr2);
sum = _A[i] + _A[idx2]
if (sum >= l2 && sum <= r2)
pairs_with_kth_bit += ptr2 - idx2 + 1;
}
if (pairs_with_kth_bit & 1)
result |= 1 << k;
}
return result;
}
var As = [
[1, 2, 3], // 2
[1, 2, 10, 11, 18, 20], // 50
[10, 26, 38, 44, 51, 70, 59, 20] // 182
];
for (let A of As){
console.log(JSON.stringify(A));
console.log(`DP, brute force: ${ f(A, 10) }, ${ bruteForce(A) }`);
console.log('');
}
var numTests = 500;
for (let i=0; i<numTests; i++){
const W = 8;
const A = [];
const n = 12;
for (let j=0; j<n; j++){
const num = Math.floor(Math.random() * (1 << (W - 1)));
A.push(num);
}
const fA = f(A, W);
const brute = bruteForce(A);
if (fA != brute){
console.log('Mismatch:');
console.log(A);
console.log(fA, brute);
console.log('');
}
}
console.log("Done testing.");

How to convert a linear index to subscripts with support for negative strides

Does an algorithm exist for converting a linear index to a list of subscripts with support for negative strides?
Background
Environments, such as MATLAB, Julia, and others, and libraries, such as NumPy, provide support for strided arrays (aka ndarrays). Strided arrays are backed by linear memory (e.g., a single underlying buffer), which stands in contrast to nested arrays, where each nested array corresponds to a dimension. For example, consider the following 2x2 matrix
[ 1 2
3 4 ]
To implement as an array of arrays
A = [ [ 1, 2 ], [ 3, 4 ] ]
where (using zero-based indexing)
a01 = A[0][1] = 2
We can represent the same 2x2 matrix as a strided array as follows (assuming row-major)
A = [ 1, 2,
3, 4 ]
where
a01 = A[ 2*0 + 1*1 ] = 2
In general, for a strided NxM matrix, the element (i,j) may be accessed via
function get( i, j ) {
return buffer[ si*i + sj*j ];
}
where buffer is the underlying data buffer and si and sj correspond to the strides along the i and j dimensions, respectively. Assuming a row-major strided array, for the 2x2 matrix above, si = 2 and sj = 1 (omitting element byte length).
In general, the strides may be computed from the array shape as follows:
function shape2strides( shape, order ) {
var out = new Array( shape.length );
var s = 1;
var i;
if ( order === 'column-major' ) {
for ( i = 0; i < shape.length; i++ ) {
out[ i ] = shape[ i ];
s *= shape[ i ];
}
return out;
} else { // row-major
for ( i = shape.length-1; i >= 0; i-- ) {
out[ i ] = shape[ i ];
s *= shape[ i ];
}
}
}
To facilitate working with strided arrays, environments/libraries often provide convenience functions which allow easy conversion between linear indices and subscripts. For example, in MATLAB, to convert from subscripts to a linear index
idx = sub2ind( size( A ), i, j )
Similarly, to convert from a linear index to subscripts in MATLAB
s = ind2sub( size( A ), idx )
Julia also has sub2ind and ind2sub. In NumPy, you can use ravel_multi_index and unravel_index.
In addition to data locality, strided arrays are convenient because they allow creating array "views" by manipulating whether a stride is negative or positive. When a stride is negative, instead of iterating from left-to-right, we iterate from right-to-left along that dimension. To support this iteration behavior, we need to determine where, in the underlying data buffer, is the first indexed element. By convention, we'll refer to this index as the "offset", which can be computed as follows
function strides2offset( shape, strides ) {
var offset = 0;
var i;
for ( i = 0; i < shape.length; i++ ) {
if ( strides[ i ] < 0 ) {
offset -= strides[i] * ( shape[i]-1 ); // increments the offset
}
}
return offset;
}
Once we have the offset, we need to modify our get( i, j ) function as follows
function get( i, j ) {
return buffer[ offset + si*i + sj*j ];
}
For a 2x2 matrix A with strides 2,1, the offset is 0, thus returning the original get function above. When the strides are 2,-1, the offset is 1; for -2,1, the offset is 2; for -2,-1, the offset is 3. Accordingly, we can generate the following matrix views (assuming row-major)
Dims: 2x2
Strides: 2,1
Offset: 0
A = [ 1, 2,
3, 4 ]
Strides: 2,-1
Offset: 1
A = [ 2, 1,
4, 3 ]
Strides: -2,1
Offset: 2
A = [ 3, 4,
1, 2 ]
Strides: -2,-1
Offset: 3
A = [ 4, 3,
2, 1 ]
The above views highlight one of the advantages of strided arrays: O(1) operations. For example, to flip a matrix left-to-right, we need only flip the sign of the stride of the second dimension (assuming row-major). To flip up-to-down, we flip the sign of the stride of the first dimension (assuming row-major). To flip left-to-right, up-to-down, we flip the sign of both strides. All the aforementioned operations do not involve touching the underlying data buffer; we simply change strided array meta data.
sub2ind
Converting from subscripts to a linear index is straightforward, even when accounting for negative strides (i.e., strided array views). For example, for a strided array of arbitrary dimensions,
function sub2ind( ...subscripts ) {
var sub;
var idx;
var s;
var n;
idx = offset;
for ( n = 0; n < shape.length; n++ ) {
sub = subscripts[ n ];
s = strides[ n ];
if ( s < 0 && offset === 0 ) { // assume want "view" index
idx -= sub * s; // always increments `idx`
} else { // assume want underlying data buffer index
idx += sub * s; // may increment or decrement `idx`
}
}
return idx;
}
Here, we allow for returning a linear index from the perspective of the view or from the perspective of the underlying data buffer. When the "offset" is 0, we assume we are always returning a linear index into the view (which may not correspond to the linear index in the underlying data buffer). In other words, for a 2x2 matrix view, (0,0) => 0, (0,1) => 1, (1,0) => 2, (1,1) => 3, always. Which makes sense from the standpoint that, when working with a view, this mapping is in accordance with intuition. When I want A(0,0), I expect the element to be located at the "first" linear index, even if that is not where that element is actually stored in underlying data buffer.
You can prove to yourself that sub2ind returns the same index for any offset as detailed above when extending element lookup to negative strides.
For example implementations, see Julia, NumPy, and stdlib.
ind2sub
The question being asked here is how to implement the reverse of sub2ind, with support for negative strides.
For positive strides (and, thus, an offset of 0), we can use modulo arithmetic to recover the subscripts. For example, consider the equation for resolving a linear index for a NxMxL strided array.
idx = offset + si*i + sj*j + sk*k
where, assuming row-major, si = nj*nk, sj = nk, sk = 1 and ni, nj, nk are the dimension sizes N, M, L, respectively. Substituting values,
idx = 0 + (nj*nk)*i + nk*j + k
which can be rearranged
idx = nk*(nj*i + j) + k
If we take the modulo of both sides using nk,
idx % nk = k
Knowing k, let's rearrange the initial equation
(idx - k) = nk*(nj*i + j)
(idx - k)/nk = nj*i + j
If we take the modulo of both sides using nj,
((idx - k)/nk) % nj = j
Knowing j, let's rearrange the initial equation to solve for i
(((idx - k)/nk) - j)/nj = i
The above algorithm generalizes to any number of dimensions and is straightforward to implement (see also Julia and NumPy).
function ind2sub( idx, order ) {
var out = new Array( shape.length );
var s;
var i;
if ( order === 'column-major' ) {
for ( i = 0; i < shape.length; i++ ) {
s = idx % shape[ i ];
idx -= s;
idx /= shape[ i ];
out[ i ] = s;
}
} else { // row-major
for ( i = shape.length-1; i >= 0; i-- ) {
s = idx % shape[ i ];
idx -= s;
idx /= shape[ i ];
out[ i ] = s;
}
}
return out;
}
The above algorithm using modulo arithmetic, however, does not support negative strides. Were we to use the same procedure above to solve for subscripts i,j,k, we would begin with the equation
idx = offset + nk*(nj*i + j) + k
which could be simplified to
idx-offset = nk*(nj*i + j) + k
The problem here, of course, is that idx-offset can be negative and effectively shifts the range of possible i,j,k values (i should be on the half-open interval [0,N); j on the interval [0,M); and k on the interval [0,L)).
This then prompts the question as to whether an algorithm exists for converting a linear index to subscripts with support for negative strides. Or in other words, is there an algorithm which, given a linear index into an underlying data buffer, can return the corresponding view subscripts?
Implementations in other languages/libraries (such as Julia and NumPy) seem to only provide support for the offset = 0 case. I am looking for something more general, which can apply to strided array views, as well.
Any pointers to existing implementations/algorithms would be greatly appreciated.
(edit - I may be dealing with the easier nd-index to flat index case, while you are focused on the reverse. It's too late to explore that task now - I'll revisit this in the morning.)
If the offset is right, I think the same formula, for converting n-d index, to flat indexing works with negative as well as positive strides:
Compare indexing of a (3,4) array with its double flip:
In [32]: x = np.arange(12).reshape(3,4)
In [33]: y = x[::-1, ::-1]
In [34]: x.strides
Out[34]: (16, 4)
In [35]: y.strides
Out[35]: (-16, -4)
Data buffer 'start' can be found with __array_interface__:
In [36]: x.__array_interface__['data']
Out[36]: (166934688, False)
In [37]: y.__array_interface__['data']
Out[37]: (166934732, False)
In [38]: 732-688
Out[38]: 44
There are 48 bytes in the buffer, but the offset for y is 44, the start of the x[2,3] element (11 in this example).
Now test the flat indexing for an x element:
In [39]: x[1,2]
Out[39]: 6 # value
In [40]: x[1:2, 2:3].__array_interface__['data'] # a view
Out[40]: (166934712, False)
In [41]: 688+(1*16)+(2*4) # offset + si*i + sj*j
Out[41]: 712
Now do the same for y:
In [42]: y[1:2, 2:3].__array_interface__['data']
Out[42]: (166934708, False)
In [43]: 732+(1*-16)+(2*-4)
Out[43]: 708
I've written a piece of code which I think solves your problem. There is more than the one function you've asked for because the other functions slightly differ from yours so I've put all of them here to avoid potential inconsistencies.The following code is not written in any particular language. However, you can find there some elements of C syntax.
function calcStrides(shape[]) {
strides[]; # Result array
currentStride = 1;
for(i = shape.size; 0 < i;) {
--i;
if(0 < shape[i]) {
strides[i] = currentStride;
currentStride *= shape[i];
} else {
strides[i] = -currentStride;
currentStride *= -shape[i];
}
}
return strides;
}
function calcOffset(shape[], strides[]) {
offset = 0;
for(i = 0; i < shape.size; ++i) {
if(shape[i] < 0) {
offset += strides[i] * (shape[i] + 1);
}
}
return offset;
}
function sub2ind(strides[], offset, subs[]) {
ind = offset;
for(i = 0; i < strides.size; ++i) {
ind += strides[i] * subs[i];
}
return ind;
};
function ind2sub(shape[], strides[], ind) {
subs[]; # Result array
for(i = 0; i < shape.size; ++i) {
if(0 < strides[i]) {
subs[i] = ind / strides[i];
ind -= subs[i] * strides[i];
} else {
absSub = ind / -strides[i];
subs[i] = -shape[i] - 1 - absSub;
ind -= absSub * -strides[i];
}
}
return subs;
}

Need a formula to calculate (i->0 to n-1 )π(n!/i!)

I need a formula to calculate the expression multiplication of (n!/i!) where i varies from 0 to n-1. So that I can implement it to a Code. trivial way exceed time limit.Any quick suggestions are welcome
x = (n!/i!) = (i+1) * (i+2) * ... * (n)
So, in pseudo-code (doing it in reverse order for increased efficiency):
x = 1;
result = 1;
for (j = n; j > 0; j--) {
x = x * j;
result = result * x; // Or + if you want the sum instead of the product
}
return result;
Note that you may need a bigint representation for x and result as they will overflow quickly.

multiple vector manipulations in Matlab

Suppose there have N vectors X_1, X_2, ..., X_N of length k each. We want all possible sums X_1(i1) + X_2(i2) + ... + X_N(iN), where i1, i2, ..., iN range from 1...k. There are k^N such sums. Is there any other way of doing it in Matlab using the built in functions, other than having N for-loops like below:
counter = 1;
for i1=1:k
for i2=1:k
.
.
.
for iN=1:k
res(counter) = X_1(i1) + X_2(i2) + ... + X_N(iN);
counter = counter + 1;
end
.
.
.
end
end
Also, this code needs to be hard-coded for the value of N, as we need N for-loops. How do we code it for any general value of N ?
A single loop of N iterations should be enough. (here it's unrolled)
sums=zeros(1,k^N);
id = 1:k^N;
i = mod(id, k)+1; id=(id-i) / k;
sums = sums + X_1(i);
i = mod(id, k)+1; id=(id-i) / k;
sums = sums + X_2(i);
...
i = mod(id, k)+1; id=(id-i) / k;
sums = sums + X_N(i);
The answer is to use ndgrid.
[s{1:N}] = ndgrid(-K:K);
res = zeros(k^N,1);
for i=1:N
res = res + s{i}(:)
end

Resources