Matlab code crashing unexpectedly - matlab

Does anyone of you have a clue of why the following code is crashing with Index exceeds matrix dimensions. error for N_SUBJ = 17 or N_SUBJ = 14, but not for example for the values 13,15,16?
N_PICS = 7
COLR = hsv;
N_COLR = size(COLR,1);
COLR = COLR(1+[0:(N_PICS-1)]*round(N_COLR/N_PICS),:);
SUBJ_COLR = hsv;
N_SUBJ_COLR = size(SUBJ_COLR,1);
SUBJ_COLR = SUBJ_COLR(1+[0:(N_SUBJ-1)]*round(N_SUBJ_COLR/N_SUBJ),:);
And also, could somebody please explain me what it's doing exactly and how it's working?

When you say crashing, I assume you mean you are seeing the error, Index exceeds matrix dimensions.? If you are seeing this error then the matrix returned by hsv does not have enough rows for the sub-sample operation you are doing.
SUBJ_COLR = SUBJ_COLR(1+[0:(N_SUBJ-1)]*round(N_SUBJ_COLR/N_SUBJ),:);
selects a subset of the original matrix. 1+[0:(N_SUBJ-1)]*round(N_SUBJ_COLR/N_SUBJ) calculates which row to select, and : means all columns.

The matrix SUBJ_COLR is 64-by-3, thus N_SUBJ_COLR is equal to 64. You're indexing into the 64 rows of SUBJ_COLR and in some cases the particular index is greater than the number of row, resulting in a Index exceeds matrix dimensions. error. So the question is really why does this snippet
1+[0:(N_SUBJ-1)]*round(N_SUBJ_COLR/N_SUBJ)
evaluate to numbers greater than 64 for some values of N_SUBJ? This expression can be rewritten as:
1+(0:round(64/N_SUBJ):round(64/N_SUBJ)*(N_SUBJ-1))
or
1:round(64/N_SUBJ):round(64/N_SUBJ)*(N_SUBJ-1)+1
where I've replaced N_SUBJ_COLR by 64 for clarity. This latter expression more clearly shows what the largest index in the vector will be and how it depends on the value of N_SUBJ. You can print out this largest index as a function of N_SUBJ:
N_SUBJ = 1:30;
round(64./N_SUBJ).*(N_SUBJ-1)+1
which returns
ans =
Columns 1 through 13
1 33 43 49 53 56 55 57 57 55 61 56 61
Columns 14 through 26
66 57 61 65 69 55 58 61 64 67 70 73 51
Columns 27 through 30
53 55 57 59
As you can see, there are several values that exceed 64. This nonlinear behavior comes down to the use of round. The integers created by the round part don't appear to get small enough fast enough as they multiply (N_SUBJ-1) which is growing in order to keep the total term less than 64. One option might be to replace round with floor, but there are probably other ways.

Related

Extract elements given 2D matrix of column indices per row from a 2D matrix in MATLAB

I tried to resample my data from a block of matrix that defined its indices. Hopefully this example can make it clear:
A=rand(18400,100);
A_IDX=randi([1 100],[18400 100]);
A_IDX consist 18400 rows and 100 columns. I wanted to extract the matrix A at the A_IDX indices. Result would be something like:
A=[1 2 3; 4 5 6];
A_IDX=[1 3; 2 3];
A_Result=[1 3; 5 6];
I tried A(:,A_IDX) but that gave me 1840x184000 matrix size, which is not what I wanted to do in the first place. Anyone can help? Thanks in advance!
We could get the linear index equivalent for those indices and then simply indexing into the input array would give us the desired output. Now, to get those linear indices, we would make use of bsxfun for the math computations related to the index computations, which would basically involve scaling and offsetting.
Indexing with 2D array of column indices
For a 2D array of column indices, we would have -
function out = take_cols(a, col_idx)
n = size(a,1);
lidx = bsxfun(#plus,(col_idx-1)*n,(1:n).');
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> col_idx
col_idx =
2 4
3 5
1 4
2 5
>> take_cols(a, col_idx)
ans =
83 48
20 50
69 34
58 51
Indexing with 2D array of row indices
For a 2D array of row indices, it would be -
function out = take_rows(a, row_idx)
[m,n] = size(a);
lidx = bsxfun(#plus,row_idx, (0:n-1)*m);
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> row_idx
row_idx =
3 2 3 1 2
4 3 4 2 4
>> take_rows(a, row_idx)
ans =
69 74 65 48 50
47 97 80 19 51
This weird monster of code will give you what you want. It generates proper subscripts for each index and converts them to linear, then just indexes A linearly.
A_IDX_aux=A_IDX';
reshape(A(sub2ind(size(A),repelem(1:size(A,1),1,size(A_IDX,1)).',A_IDX_aux(:))),[size(A,1), size(A_IDX,2)]).';
I find my solution for this task too, but not so fast, as Divakar and Ander :)
Behold:
res = cell2mat(arrayfun( #(x) A(x,A_IDX(x,:)), (1:size(A,1))', 'UniformOutput',false));
It use cell2mat and I suppose it is not so fast as bsxfun, but hope is still alive and I was curios to test all the 3 solutions. And I got unobvious results!
Elapsed time is 0.000058 seconds. % Divakar
Elapsed time is 0.000077 seconds. % Andres
Elapsed time is 0.000339 seconds. % Me
This mean bsxf is fastest! But using right indexing give fast result too! And my solution was really slow. I suppose it's because of 'UniformOutput', false - I forced to convert to cells and then back, so it slow my method a lot.
Conclusion:
If you can use bsxf - use it!
Despite the fact that my method looks more visually pleasing than that of Andres, it is still slower.
So there is no any sense to post this answer :D I spend some time for current work, maybe it will help someone in future

Element-by-element max values in multidimensional matrix

I have a few multidimensional matrices of dimensions mxnxt, where each element in mxn is an individual sensor input, and t is time. What I want to do is analyse only the peak values for each element in mxn over t, so I would end up with a single 2D matrix of mxn containing only max values.
I know there are are ways to get a single overall max value, but is there a way to combine this with element-by-element operations like bsxfun so that it examines each individual element over t?
I'd be grateful for any help you can give because I'm really stuck at the moment. Thanks in advance!
Is this what you want?
out = max(A,[],3); %// checking maximum values in 3rd dimension
Example:
A = randi(50,3,3,3); %// Random 3x3x3 dim matrix
out = max(A,[],3);
Results:
A(:,:,1) =
35 5 8
38 12 42
23 46 27
A(:,:,2) =
50 6 39
4 49 41
23 1 44
A(:,:,3) =
5 41 10
20 22 14
13 46 8
>> out
out =
50 41 39
38 49 42
23 46 44
You can call max() with the matrix and select the dimension (look the documentation) on which the operation will be calculated, e.g
M = max(A,[],3)

Most repeated values

I know how to check an 8-neighbourhood in matlab (i.e; nlfilter). But, I want to assign the value which is more repeated to the center value. So, say for instance that I have the following values in the 8-neighbourhood:
2-values = 56
3-values = 64
1-value = 70
1-value = 87
1-value = 65
In this case we would assign 64 to the center pixel.
How can we do that?
Thanks.
I think you want either the mode or the histc function.
M=mode(X) for vector X computes M as the sample mode, or most
frequently
occurring value in X.
Example with your data:
x = [56 56 64 64 64 70 87 65];
mode(x)
ans =
64
But this will only get you the most frequently occurring value.
If you want the count of each unique item in the array, you could do,
unqx = unique(x);
unqx =
56 64 65 70 87
valueCount = histc(x, unqx)
ans =
2 3 1 1 1
You could then sort this and take the first N values
valueCount = sort(valueCount, 'descend');
% Use unqx(valueCount(1:N))

How do I select n elements of a sequence in windows of m ? (matlab)

Quick MATLAB question.
What would be the best/most efficient way to select a certain number of elements, 'n' in windows of 'm'. In other words, I want to select the first 50 elements of a sequence, then elements 10-60, then elements 20-70 ect.
Right now, my sequence is in vector format(but this can easily be changed).
EDIT:
The sequences that I am dealing with are too long to be stored in my RAM. I need to be able to create the windows, and then call upon the window that I want to analyze/preform another command on.
Do you have enough RAM to store a 50-by-nWindow array in memory? In that case, you can generate your windows in one go, and then apply your processing on each column
%# idxMatrix has 1:50 in first col, 11:60 in second col etc
idxMatrix = bsxfun(#plus,(1:50)',0:10:length(yourVector)-50); %'#
%# reshapedData is a 50-by-numberOfWindows array
reshapedData = yourVector(idxMatrix);
%# now you can do processing on each column, e.g.
maximumOfEachWindow = max(reshapedData,[],1);
To complement Kerrek's answer: if you want to do it in a loop, you can use something like
n = 50
m = 10;
for i=1:m:length(v)
w = v(i:i+n);
% Do something with w
end
There's a slight issue with the description of your problem. You say that you want "to select the first 50 elements of a sequence, then elements 10-60..."; however, this would translate to selecting elements:
1-50
10-60
20-70
etc.
That first sequence should be 0-10 to fit the pattern which of course in MATLAB would not make sense since arrays use one-indexing. To address this, the algorithm below uses a variable called startIndex to indicate which element to start the sequence sampling from.
You could accomplish this in a vectorized way by constructing an index array. Create a vector consisting of the starting indices of each sequence. For reuse sake, I put the length of the sequence, the step size between sequence starts, and the start of the last sequence as variables. In the example you describe, the length of the sequence should be 50, the step size should be 10 and the start of the last sequence depends on the size of the input data and your needs.
>> startIndex = 10;
>> sequenceSize = 5;
>> finalSequenceStart = 20;
Create some sample data:
>> sampleData = randi(100, 1, 28)
sampleData =
Columns 1 through 18
8 53 10 82 82 73 15 66 52 98 65 81 46 44 83 9 14 18
Columns 19 through 28
40 84 81 7 40 53 42 66 63 30
Create a vector of the start indices of the sequences:
>> sequenceStart = startIndex:sequenceSize:finalSequenceStart
sequenceStart =
10 15 20
Create an array of indices to index into the data array:
>> index = cumsum(ones(sequenceSize, length(sequenceStart)))
index =
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
>> index = index + repmat(sequenceStart, sequenceSize, 1) - 1
index =
10 15 20
11 16 21
12 17 22
13 18 23
14 19 24
Finally, use this index array to reference the data array:
>> sampleData(index)
ans =
98 83 84
65 9 81
81 14 7
46 18 40
44 40 53
Use (start : step : end) indexing: v(1:1:50), v(10:1:60), etc. If the step is 1, you can omit it: v(1:50).
Consider the following vectorized code:
x = 1:100; %# an example sequence of numbers
nwind = 50; %# window size
noverlap = 40; %# number of overlapping elements
nx = length(x); %# length of sequence
ncol = fix((nx-noverlap)/(nwind-noverlap)); %# number of sliding windows
colindex = 1 + (0:(ncol-1))*(nwind-noverlap); %# starting index of each
%# indices to put sequence into columns with the proper offset
idx = bsxfun(#plus, (1:nwind)', colindex)-1; %'
%# apply the indices on the sequence
slidingWindows = x(idx)
The result (truncated for brevity):
slidingWindows =
1 11 21 31 41 51
2 12 22 32 42 52
3 13 23 33 43 53
...
48 58 68 78 88 98
49 59 69 79 89 99
50 60 70 80 90 100
In fact, the code was adapted from the now deprecated SPECGRAM function from the Signal Processing Toolbox (just do edit specgram.m to see the code).
I omitted parts that zero-pad the sequence in case the sliding windows do not evenly divide the entire sequence (for example x=1:105), but you can easily add them again if you need that functionality...

How to compare the pairs of coordinates most efficiently without using nested loops in Matlab?

If I have 20 pairs of coordinates, whose x and y values are say :
x y
27 182
180 81
154 52
183 24
124 168
146 11
16 90
184 153
138 133
122 79
192 183
39 25
194 63
129 107
115 161
33 14
47 65
65 2
1 124
93 79
Now if I randomly generate 15 pairs of coordinates (x,y) and want to compare with these 20 pairs of coordinates given above, how can I do that most efficiently without nested loops?
If you're trying to see if any of your 15 randomly generated coordinate pairs are equal to any of your 20 original coordinate pairs, an easy solution is to use the function ISMEMBER like so:
oldPts = [...]; %# A 20-by-2 matrix with x values in column 1
%# and y values in column 2
newPts = randi(200,[15 2]); %# Create a 15-by-2 matrix of random
%# values from 1 to 200
isRepeated = ismember(newPts,oldPts,'rows');
And isRepeated will be a 15-by-1 logical array with ones where a row of newPts exists in oldPts and zeroes otherwise.
If your coordinates are 1) actually integers and 2) their span is reasonable (otherwise use sparse matrix), I'll utilize a simple truth table. Like
x_0= [27 180 ...
y_0= [182 81 ...
s= [200 200]; %# span of coordinates
T= false(s);
T(sub2ind(s, x_0, y_0))= true;
%# now obtain some other coordinates
x_1= [...
y_1= [...
%# and common coordinates of (x_0, y_0) and (x_1, y_1) are just
T(sub2ind(s, x_1, y_1))
If your original twenty points aren't going to change, you'd get better efficiency if you sorted them O(n log n); then you could see if each random point was in the list with a O(log n) search.
If your "original" points list changes (insertions / deletions), you could get equivalent performance with a binary tree.
BUT: If the number of points you're working with is really as low as in your question, your double loop might just be the fastest method! Algorithms with low Big-O curves will be faster as the amount of data gets really big, but it's often at the cost of a one-time slowdown (in your case, the sort) - and with only 15x20 data points... There won't be a human-perceptible difference; you might see one if you're timing it on your system clock. Or you might not.
Hope this helps!