What is another similar logic that is faster than ismember? - matlab

Continue my research,
I need another similar logic with ismember that has execution time faster.
this part of my code and the matrix.
StartPost =
14 50 30 1 72 44 76 68 63 80 25 41;
14 50 30 1 61 72 42 46 67 77 81 27;
35 23 8 54 19 70 48 75 66 79 2 84;
35 23 8 54 82 72 78 68 19 2 48 66;
69 24 36 52 63 47 5 18 11 82 1 15;
69 24 36 52 48 18 1 12 80 63 6 84;
73 38 50 7 1 33 24 68 29 20 62 84;
73 38 50 7 26 61 65 32 22 18 2 69]
for h=2:2:8,
...
done=all(ismember(StartPost(h,1:4),StartPost(h-1,1:4)));
...
end
I checked that code by using Profile viewer. I got that in this part that made my code took time execution slowly.
Anyone has experience about this logic, please share. thanks

MATLAB has several undocumented built-in functions which can help you achieve the same results as other functions, only faster.
In your case, you can use ismembc:
done = all(ismembc(StartPost(h, 1:4), sort(StartPost(h-1, 1:4)))));
Note that ismembc(A, B) requires matrix B to be sorted and not to contain any NaNs values.
Here's the execution time difference for your example:
tic
for h = 2:2:8
done = all(ismember(StartPost(h, 1:4), StartPost(h-1, 1:4)));
end
toc
Elapsed time is 0.029888 seconds.
tic
for h = 2:2:8
done = all(ismembc(StartPost(h, 1:4), sort(StartPost(h-1, 1:4))));
end
toc
Elapsed time is 0.006820 seconds.
This is about ~50 times faster.

Related

using recursion for solving Euler 18 in q

I have written this code in q for solving Euler 18 problem,as described in the link below, using recursion.
https://stackoverflow.com/questions/8002252/euler-project-18-approach
Though the code works, it is not efficient and gets stack overflow at pyramids of sizes greater than 3000. How could I make this code much more efficient.I believe the optimum code can be less than 30 characters.
pyr:{[x]
lsize:count x;
y:x;
$[lsize <=1;y[0];
[.ds.lastone:x[lsize - 1];
.ds.lasttwo:x[lsize - 2];
y:{{max (.ds.lasttwo)[x] +/: .ds.lastone[x],.ds.lastone[x+1]}each til count .ds.lasttwo};
$[(count .ds.lasttwo)=1;y:{max (.ds.lasttwo) +/: .ds.lastone[x],.ds.lastone[x+1]}0;y:y[]];
x[lsize - 2]:y;
pyr[-1_x]]]
}
To properly implement this logic in q you need to use adverbs.
First, to quickly find the rolling maximums you can use the prior adverb. For example:
q)input:(75;95 64;17 47 82;18 35 87 10;20 04 82 47 65;19 01 23 75 03 34;88 02 77 73 07 63 67;99 65 04 28 06 16 70 92;41 41 26 56 83 40 80 70 33;41 48 72 33 47 32 37 16 94 29;53 71 44 65 25 43 91 52 97 51 14;70 11 33 28 77 73 17 78 39 68 17 57;91 71 52 38 17 14 91 43 58 50 27 29 48;63 66 04 68 89 53 67 30 73 16 69 87 40 31;04 62 98 27 23 09 70 98 73 93 38 53 60 04 23)
q)last input
4 62 98 27 23 9 70 98 73 93 38 53 60 4 23
q)1_(|) prior last input
62 98 98 27 23 70 98 98 93 93 53 60 60 23
That last line outputs the a vector with the maximum value between each successive pair in the input vector. Once you have this you can add it to the next row and repeat.
q)foo:{y+1_(|) prior x}
q)foo[input 14;input 13]
125 164 102 95 112 123 165 128 166 109 122 147 100 54
Then, to apply this function over the whole use the over adverb:
q)foo over reverse input
,1074
EDIT: The approach above can be generalized further.
q provides a moving max function mmax. With this you can find "the x-item moving maximum of numeric y", which generalizes the use of prior above. For example, you can use this to find the moving maximum of pairs or triplets in the last row of the input:
q)last input
4 62 98 27 23 9 70 98 73 93 38 53 60 4 23
q)2 mmax last input
4 62 98 98 27 23 70 98 98 93 93 53 60 60 23
q)3 mmax last input
4 62 98 98 98 27 70 98 98 98 93 93 60 60 60
mmax can be used to simplify foo above:
q)foo:{y+1_ 2 mmax x}
What's especially nice about this is that it can be used to generalize to variants of this problem with wider triangles. For example, the triangle below has two more values on each row and from any point on a row you can move to the left, middle, or right of the row below it.
5
5 6 7
6 7 3 9 1

Matlab: select submatrix from matrix by certain criteria

I have a matrix A
A=[f magic(10)]
A=
931142103 92 99 1 8 15 67 74 51 58 40
931142103 98 80 7 14 16 73 55 57 64 41
931142103 4 81 88 20 22 54 56 63 70 47
459200101 85 87 19 21 3 60 62 69 71 28
459200101 86 93 25 2 9 61 68 75 52 34
459200101 17 24 76 83 90 42 49 26 33 65
459200101 23 5 82 89 91 48 30 32 39 66
37833100 79 6 13 95 97 29 31 38 45 72
37833100 10 12 94 96 78 35 37 44 46 53
37833100 11 18 100 77 84 36 43 50 27 59
The first column are firm codes. The rest columns are firms' data, with each row referring to the firm in Column 1 in a given year. Notice that years may not be balance for every firms.
I would like to subtract sub-matrices according to the first column. For instance, for A(1:3,2:11) for 931142103:
A(1:3,2:11)
ans =
92 99 1 8 15 67 74 51 58 40
98 80 7 14 16 73 55 57 64 41
4 81 88 20 22 54 56 63 70 47
Same as 459200101 (which would be A(4:7,2:11)) and A(8:10,2:11) for 37833100.
I get a sense that the code should like this:
indices=find(A(:,1));
obs=size(A(:,1));
for i=1:obs,
if i==indices(i ??)
A{i}=A(??,2:11);
end
end
I have difficulties in indexing these complicated codes: 459200101 and 37833100 in order to gather them together. And how can I write the rows of my submatrix A{i}?
Thanks so much!
One approach with arrayfun -
%// Get unique entries from first column of A and keep the order
%// with 'stable' option i.e. don't sort
unqA1 = unique(A(:,1),'stable')
%// Use arrayfun to select each such submatrix and store as a cell
%// in a cell array, which is the final output
outA = arrayfun(#(n) A(A(:,1)==unqA1(n),:),1:numel(unqA1),'Uni',0)
Or this -
[~,~,row_idx] = unique(A(:,1),'stable')
outA = arrayfun(#(n) A(row_idx==n,:),1:max(row_idx),'Uni',0)
Finally, you can verify results with a call to celldisp(outA)
If values in column 1 always appear grouped (as in your example), you can use mat2cell as follows:
result = mat2cell(A, diff([0; find(diff(A(:,1))); size(A,1)]));
If they don't, just sort the rows of A according to column 1 before applying the above:
A = sortrows(A,1);
result = mat2cell(A, diff([0; find(diff(A(:,1))); size(A,1)]));
If you don't mind the results internally not being ordered, you can use accumarray for this:
[~,~,I] = unique(A(:,1),'stable');
partitions = accumarray(I, 1:size(A,1), [], #(I){A(I,2:end)});

Matlab: 3D Surface Plot of values from own vectors

I have 3 vectors with values for coordinates (X,Y,Z) and I want to plot them as a surface. I have tried all sorts of solutions from here and other forums and cannot for the life of me get it to look like anything that makes sense. I have a picture that can describe the situation better but I can't post it as I don't have enough reputation. Please help. Thank you.
EDIT: This is the link to the picture :
In the picture, the origin of each vector arrow represents the point in a 3D coordinate, with the length of the vector arrow giving the magnitude of the required torque to move at that point in 3D space.
Right now, the data is separated in line vectors with each point's coordinate: so that's one vector for the X, one for Y. Z is one line inside a 3 line matrix as the whole matrix describes the required torque in a 3 coordinate axes.
I've tried using meshgridon the X and Y vectors and then attributed the Z value using griddataand then surfbut I'm not getting something that looks like the original:
The plot is linear but I'm pretty sure the data is not... at least not that linear.
It seems like you want want to plot the single points decribed by the vectors, here you have an old answer of mine (as a bonus you will have nice colorful plots 'cause that's what the original question asked):
Assuming Data=[Vec1,Vec2,Vec3,...] and VecN=[Xn,Yn,Zn]'
"
If you want to plot points, you can define an RGB color and plot single points with hold on like this:
hold on
for i=1:length(Data(:,1))
plot3(Data(i,1),Data(i,2),Data(i,3),'Color',[(i/100*255)/255 0/255 (255-(i/100*255))/255],'LineWidth',2)
end
shg
"
Managed to solve the problem. As mentioned, the data was not uniform and because of that, surfwas jumping from one end of the plot to the other, creating a total mess. Solved it by organising the values linearly using linspaceand then using those values to create the meshgrid and then assign the Z values using griddata with a cubic interpolation.. Managed to produce proper looking surface plots with the data on hand.
Plot each data point separately within a loop:
figure; hold on; grid on;
for i = 1:length(x)
stem3(x(i),y(i),z(i));
end
Don't forget to add hold on. Use "Rotate 3D" button from the toolbar in the figure window if the plot was shown in 2D at first.
You can use griddata parameter to natural, cubic or v4. This will do interpolation and make your graph with non-uniform data smooth
Below is a sample MATLAb code
x=[32 20 67 1 98 34 57 65 24 82 47 55 8 51 13 14 18 30 37 39 10 33 21 26 38 81 83 60 95 22 17 5 72 46 99 52 12 25 96 29 70 85 43 69 19 78 97 31 89 53 2 91 48 71 61 15 36 84 94 50 11 80 6 7 49 74 9 88 40 79 27 68 73 64 63 59 86 23 35 58 45 28 100 42 93 87 16 90 41 66 54 92 77 4 62 76 75 56 3 44];
y=[96 75 24 9 83 49 27 77 3 23 17 31 40 13 7 52 51 21 98 47 64 79 78 91 44 16 15 100 84 99 63 68 70 30 54 76 97 73 33 5 88 8 71 66 62 25 60 42 72 45 18 11 28 59 89 65 10 55 69 81 12 26 20 95 87 41 74 50 93 22 43 90 14 34 82 35 56 38 80 32 1 57 6 36 37 61 29 58 2 48 4 46 67 53 92 86 94 19 39 85];
z=[55 31 11 45 83 36 86 49 15 57 42 46 8 94 88 47 54 81 98 41 32 35 56 85 9 89 37 60 23 62 67 100 78 76 73 80 10 20 68 34 77 93 1 63 53 12 22 99 91 40 84 24 33 3 43 19 92 97 6 82 64 25 26 79 95 4 44 58 5 21 70 29 65 87 96 90 51 14 18 2 72 28 71 39 52 7 27 59 50 61 48 30 66 69 17 13 74 16 75 38];
xlin = linspace(min(x), max(x), 100);
ylin = linspace(min(y), max(y), 100);
[X,Y] = meshgrid(xlin, ylin);
% Z = griddata(x,y,z,X,Y,'natural');
% Z = griddata(x,y,z,X,Y,'cubic');
Z = griddata(x,y,z,X,Y,'v4');
mesh(X,Y,Z)
axis tight; hold on
plot3(x,y,z,'.','MarkerSize',15)

MATLAB: extracting groups of columns into a submatrix?

I have a data-set, in which I want to extract columns 1-3, 7-9, 13-15, all the way to the end of the matrix
As an example, I've used the standard magic function to create a matrix
A=magic(10)
A =
92 99 1 8 15 67 74 51 58 40
98 80 7 14 16 73 55 57 64 41
4 81 88 20 22 54 56 63 70 47
85 87 19 21 3 60 62 69 71 28
86 93 25 2 9 61 68 75 52 34
17 24 76 83 90 42 49 26 33 65
23 5 82 89 91 48 30 32 39 66
79 6 13 95 97 29 31 38 45 72
10 12 94 96 78 35 37 44 46 53
11 18 100 77 84 36 43 50 27 59
I know that I can extract single columns starting at 1, in intervals of 3 with the command:
Aex=a(:,1 : 3 : end)
Aex =
92 8 74 40
98 14 55 41
4 20 56 47
85 21 62 28
86 2 68 34
17 83 49 65
23 89 30 66
79 95 31 72
10 96 37 53
11 77 43 59
Say I want to extract groups of columns instead (e.g. column 1-3, 7-9 etc.).
Is there a way to do this without having to manually point out all the column numbers?
Thanks for your help!
Rasmus
Is this what you are looking for:
Aex = A(:,[1:3 7:9])
?
I am assuming that you would like the result all concatenated into another large matrix?
If that is the case, try this one on for size:
result = A(diag(0:2)*ones(3,floor((size(A,2) - 3)/6) + 1) + ...
ones(3,floor((size(A,2) - 3)/6) + 1)*diag(1:6:(size(A,2)-3)))
That could probably be shortened with some matrix math rules. You could also parameterize the values so that it can be modified to do more than what this problem expects, (and also might make more sense),
a = 3;
b = 6;
result = A(diag(0:a-1)*ones(a,floor((size(A,2) - a)/b) + 1) + ...
ones(a,floor((size(A,2) - a)/b) + 1)*diag(1:b:(size(A,2)-a)))
where a is the size of "group" (length([1 2 3]) = length([7 8 9]) = ... = 3), etc. and b is the column spacing ([1...7...13...] in your example)
If you would like them separated, I put them in cells here, but they can go to wherever you need:
a = 3;
b = 6;
results = {};
for Cols = 1:b:(size(A,2)-a)
results{end+1} = A(:, Cols:(Cols+2));
end
I didn't check the speed of either of these, but I think the first one may be faster. You may want to split it up into terms so it's more readable, I just did it to fit on a single line (which isn't always the best way of writing code).
The simple way to do this:
M = magic(10);
n = size(M,2)
idx = sort([1:3:n 2:3:n 3:3:n])
M(:,idx)
If however, the pattern of removal is simpler than the pattern of colums that you want to keep you could use this instead:
A = magic(10);
B = A;
B(:,4:3:end)=[];
B(:,4:3:end)=[]; %Yes 3x the same line of code.
B(:,4:3:end)=[];

Sliding window algorithm for activity recognition

I want to write a sliding window algorithm for use in activity recognition.
The training data is <1xN> so I'm thinking I just need to take (say window_size=3) the window_size of data and train that. I also later want to use this algorithm on a matrix
.
I'm new to matlab so i need any advice/directions on how to implement this correctly.
The short answer:
%# nx = length(x)
%# nwind = window_size
idx = bsxfun(#plus, (1:nwind)', 1+(0:(fix(nx/nwind)-1))*nwind)-1;
idx will be a matrix of size nwind-by-K where K is the number of sliding windows (ie each column contains the indices of one sliding window).
Note that in the code above, if the last window's length is less than the desired one, it is dropped. Also the sliding windows are non-overlapping.
An example to illustrate:
%# lets create a sin signal
t = linspace(0,1,200);
x = sin(2*pi*5*t);
%# compute indices
nx = length(x);
nwind = 8;
idx = bsxfun(#plus, (1:nwind)', 1+(0:(fix(nx/nwind)-1))*nwind)-1;
%'# loop over sliding windows
for k=1:size(idx,2)
slidingWindow = x( idx(:,k) );
%# do something with it ..
end
%# or more concisely as
slidingWindows = x(idx);
EDIT:
For overlapping windows, let:
noverlap = number of overlapping elements
then the above is simply changed to:
idx = bsxfun(#plus, (1:nwind)', 1+(0:(fix((nx-noverlap)/(nwind-noverlap))-1))*(nwind-noverlap))-1;
An example to show the result:
>> nx = 100; nwind = 10; noverlap = 2;
>> idx = bsxfun(#plus, (1:nwind)', 1+(0:(fix((nx-noverlap)/(nwind-noverlap))-1))*(nwind-noverlap))-1
idx =
1 9 17 25 33 41 49 57 65 73 81 89
2 10 18 26 34 42 50 58 66 74 82 90
3 11 19 27 35 43 51 59 67 75 83 91
4 12 20 28 36 44 52 60 68 76 84 92
5 13 21 29 37 45 53 61 69 77 85 93
6 14 22 30 38 46 54 62 70 78 86 94
7 15 23 31 39 47 55 63 71 79 87 95
8 16 24 32 40 48 56 64 72 80 88 96
9 17 25 33 41 49 57 65 73 81 89 97
10 18 26 34 42 50 58 66 74 82 90 98