Keeping track of indices after sorting - arrays

So I have several arrays of positions, velocities, etc in 3D-space (vec3(x,y,z)) and another array which holds indices that are used to look-up in the vec3 arrays. This is all for a particle-system representing cloth (in case anyone was wondering).
The second array is far larger than the position array because for each particle, the second array represents a type of "spring" relationship with another particle. So for example, any given particle might have a "spring" attached to 3 different particles. So the first bunch of indices in the second array might look like this: [0, 1, 0, 2, 0, 3, 0, 4, ...]
The problem here is that the position array is sorted based on a hash function used for finding neighbors in a uniform grid. This means that the indices held in the 2nd array will no longer be valid. I'm trying to figure out a way to sort the positions and then still use the 2nd array to index properly.
One thought that I've had would be to have a 3rd array which stores the new indices based on the sorting function, but I am not sure how I could actually go about doing this.
Also, the reason the data is separated rather than being put into an object is that this is being run in CUDA and it is an optimization for speed/memory.
Is there a simple way of going about this? Thanks for any help.

Would something like this work?
Transfer your array of vec3(x, y, z)s into an array of pair(index, vec3(x, y, z)). Sort this new array by taking the hash function of the second element. The result will be a sorted array of pair(index, vec3(x, y, z)), where index is the vector's initial position in the array. Then, use this to construct a third "lookup" array of integers whose indices are the initial indices and whose values are the new values. Now to get a vector from your second array you do something like vector_pairs[lookup[spring[4]]].second.
Python-ish pseudocode:
vecs = ...
spring = ...
pair_vecs = [(index, vec) for index, vec in enumerate(vecs)]
pair_vecs.sort(key=lambda index, vec: hash(vec))
lookup = [0] * len(pair_vecs)
for new_index, (initial_index, vec) in enumerate(pair_vecs):
lookup[initial_index] = new_index

Related

Arrays with ordinal set of values for index?

I am pulling my hair over this one.
I read in my data structures text, that the index of an array usually uses a consecutive range of integers, but the index can have any ordinal set of values.
I think I understand the consecutive range part, like 0,1,2...(in most languages) positions in an array where elements are placed, but what does an ordinal set of values mean?
EDIT
Here's a paragraph from the text:
"In computer programming, a group of homogeneous elements of a specific data type is know as an array. Arrays hold a series of data elements, usually of the same size and data type. The individual elements are accessed by their position in the array. This position is given by an index, also called the subscript. The index usually uses a consecutive range of integers, but the index can have any ordinal set of values."
It means, that usually array is indexed like [0, 1, 2, 3, ... k], but it may happen, that some particular array data-structure, can have a ordinal set of index values - index values can be like [1, 3, 5, 7.. k].

Matlab: Refer to multiple, non consecutive elements

In Matlab is there any way to refer to multiple, non consecutive elements in a 1 dimensional array in the same line, eg. something like:
mean(strength(1:4,17:20))
I want to calculate the mean of 1st to 4th elements and the 17th to 20th elements in an array called strength etc. Except obviously a comma wouldn't work, because that would be double indexing, as if it was a matrix, when it's 1D. Is there another symbol you could use in place of the comma to do this, or would you need another technique to do this?
Like Andras says in his comment, you need a vector of the indices you wish to include in the calculation of the mean:
Just as you would reference the ith value of a vector with strength(i), you can have a vector instead of i, which will give you all of the specified values as another vector:
indexVector = [1:4, 17:20];
values = strength(indexVector);
This will give you a 1D vector of length 8 containing values 1:4 and 17:20 of the original strength vector, which would allow you to use mean(strength).
You can bypass writing these to variables, and just use:
mean(strength([1:4, 17:20]))

Dynamic slicing of Matlab array

I have an n-dimensional array A and want to slice it dynamically, i.e., given a list of array dimensions, like [2 4], and a list of values, like [6 8], I want
B = A(:,6,:,8,:,:,:,:,...)
List lengths are unknown. Using eval would work but is not an option. This question is a generalization of a previous post to multiple indices and dimensions without a for-loop.
You can still use the previous post I linked to (which I originally flagged as a duplicate) to answer your question. This original post only slices in one dimension. I originally flagged it as a duplicate and closed it because all you need to do is replace one line of code in the original post's accepted answer to achieve what you want. However, because it isn't that obvious, I have decided to reopen the question and answer the question for you.
Referring to the previous post, this is what Andrew Janke (the person with the accepted answer on the linked post) did (very clever I might add):
function out = slice(A, ix, dim)
subses = repmat({':'}, [1 ndims(A)]);
subses{dim} = ix;
out = A(subses{:});
Given a matrix A, an index number ix and the dimension you want to access dim, the above function would equivalently perform:
out = A(:, :, ..., ix, :, :,...:);
^ ^ ^ ^
dimensions --> 1 2 dim dim+1
You would access your desired dimension in dim, and place what value you want to use to slice into that dimension. As such, you'd call it like this:
out = slice(A, ix, dim);
How the function works is that subses would generate a cell array of ':' strings (that will eventually be converted into ':' operators) that is as long as the total number of dimensions of A. Next, you would access the element at dim, which corresponds to the dimension you want and you would replace this with ix. You would then unroll this cell array so that we would access A in the manner that you see in the above equivalent statement.
Who would have thought that you can use strings to index into an array!?
Now, to generalize this, all you have to do is make one small but very crucial change. ix would now be a vector of indices, and dim would be a vector of dimensions you want to access. As such, it would look something like this:
function out = slice(A, ix, dim)
subses = repmat({':'}, [1 ndims(A)]);
subses(dim) = num2cell(ix);
out = A(subses{:});
The only difference we see here is the second line of the code. We have to use num2cell so that you can convert each element into a cell array, and we slice into this cell array to replace the : operators with your desired dimensions. Note that we are using () braces and not {} braces. () braces are used to slice through cell arrays while {} are used to access cell array contents. Because we are going to assign multiple cells to subses, () is needed. We then perform our slicing in A accordingly.
As such, given your problem and with the above modifications, you would do:
out = slice(A, [6 8], [2 4]);
Be advised that ix and dim must contain the same number of elements and they must be 1D. Also, ix and dim should be sensible inputs (i.e. not floating point and negative). I don't do this error checking because I'm assuming you know what you're doing and you're smart enough to know how to use this properly.
Good luck!

Split array into smaller unequal-sized arrays dependend on array-column values

I'm quite new to MatLab and this problem really drives me insane:
I have a huge array of 2 column and about 31,000 rows. One of the two columns depicts a spatial coordinate on a grid the other one a dependent parameter. What I want to do is the following:
I. I need to split the array into smaller parts defined by the spatial column; let's say the spatial coordinate are ranging from 0 to 500 - I now want arrays that give me the two column values for spatial coordinate 0-10, then 10-20 and so on. This would result in 50 arrays of unequal size that cover a spatial range from 0 to 500.
II. Secondly, I would need to calculate the average values of the resulting columns of every single array so that I obtain per array one 2-dimensional point.
III. Thirdly, I could plot these points and I would be super happy.
Sadly, I'm super confused since I miserably fail at step I. - Maybe there is even an easier way than to split the giant array in so many small arrays - who knows..
I would be really really happy for any suggestion.
Thank you,
Arne
First of all, since you wish a data structure of array of different size you will need to place them in a cell array so you could try something like this:
res = arrayfun(#(x)arr(arr(:,1)==x,:), unique(arr(:,1)), 'UniformOutput', 0);
The previous code return a cell array with the array splitted according its first column with #(x)arr(arr(:,1)==x,:) you are doing a function on x and arrayfun(function, ..., 'UniformOutput', 0) applies function to each element in the following arguments (taken a single value of each argument to evaluate the function) but you must notice that arr must be numeric so if not you should map your values to numeric values or use another way to select this values.
In the same way you could do
uo = 'UniformOutput';
res = arrayfun(#(x){arr(arr(:,1)==x,:), mean(arr(arr(:,1)==x,2))), unique(arr(:,1)), uo, 0);
You will probably want to flat the returning value, check the function cat, you could do:
res = cat(1,res{:})
Plot your data depends on their format, so I can't help if i don't know how the data are, but you could try to plot inside a loop over your 'res' variable or something similar.
Step I indeed comes with some difficulties. Once these are solved, I guess steps II and III can easily be solved. Let me make some suggestions for step I:
You first define the maximum value (maxValue = 500;) and the step size (stepSize = 10;). Now it is possible to iterate through all steps and create your new vectors.
for k=1:maxValue/stepSize
...
end
As every resulting array will have different dimensions, I suggest you save the vectors in a cell array:
Y = cell(maxValue/stepSize,1);
Use the find function to find the rows of the entries for each matrix. At each step k, the range of values of interest will be (k-1)*stepSize to k*stepSize.
row = find( (k-1)*stepSize <= X(:,1) & X(:,1) < k*stepSize );
You can now create the matrix for a stepk by
Y{k,1} = X(row,:);
Putting everything together you should be able to create the cell array Y containing your matrices and continue with the other tasks. You could also save the average of each value range in a second column of the cell array Y:
Y{k,2} = mean( Y{k,1}(:,2) );
I hope this helps you with your task. Note that these are only suggestions and there may be different (maybe more appropriate) ways to handle this.

How to store vector coordinates in Matlab

what's the best way to store vector coordinates in Matlab?
For example, h is the height of the image, w is the width, how can I do this (pseudocode):
vectors = [];
for i=1:h
for j=1:w
vectors += p(i,j);
end
end
To get the kth p object from vectors, I can use vector(k).
Thank you very much.
Array growth in MATLAB works by indexing past the last element:
vectors(end+1) = p(i,j);
Conventional wisdom is that it is better to pre-allocate your array and use indexing, but automatic array growth has become much more efficient, especially for cells and arrays of non-builtin objects.
However, you can just get what you want out of p directly via [ii,jj] = ind2sub(size(p),k); p(jj,ii). Note the order jj,ii to match your loop semantics, which would create a vector that indexes the elements of p in a row-major order vs. MATLAB's native column-major ordering. That is, p(2) refers to row 2, column 1 of p, but your vectors(2) would contain to row 1, column 2 of p using your loop order.
You can use p(k) directly. It is equivalent to p(i,j) where [i,j] = ind2sub([h w], k).
Documentation for ind2sub
Unless I didn't understand your question…

Resources