How to convert members of a matrix in a specific constrains value in MATLAB? - matlab

If
a =
1
2
3
3.5
5
6
6.25
8
9
9.75
11
12
13
14
15
How it is possible to switch numbers which are in a specific constrains, into the smaller part of constrain?
In other word, if b=min(a) & c=b+threshold
b<a<c => a=b.
It means, in this example, let's assume threshold=3. Then "a" should change into a matrix which min(a):min(a)+threshold =[min(a)]. This procedure should continue to the last array of "a"matrix by adding each time the amount of threshold. The result should be like this:
a=
1
1
1
1
5
5
5
5
9
9
9
9
13
13
13

I guess finally I found a solution for that. Sorry if I couldn't explain better my intention and mislead you. Here is the code:
a = [1 2 3 3.5 5 6 6.25 8 9 9.75 11 12 13 14 15]';
b = min(a);
threshold=4;
c=b;
for i=1:size(a,1)
c =c+threshold;
a((a > b & a < c)) = b;
b=b+threshold;
if c==max(a);
break
end
end
P.S. threshold change to "threshold=4" instead of "3"

Logical indexing
Edit, based on the comment thread
I can't think of a way to avoid a loop here, nor am I really sure how to constrain it efficiently, but the general process is the same:
% Initial conditions
threshold = 3;
a = [1 2 3 3.5 5 6 6.25 8 9 9.75 11 12 13 14 15];
b = min(a);
c = b + threshold;
a((a > b & a < c)) = b;
for/while/if % Need some way to constrain the loop
b = c;
c = c+threshold;
a((a > b & a < c)) = b;
end

Related

What is this piece of code in Matlab doing

This is a snippet from a program I am trying to understand. I have changed the variable names for easier understanding. I haven't done much coding in MatLab so I can't really understand what's happening. When I kept a=magic(4) and got the output from this code I thought it was sorting or something but it doesn't seem so with the other input
a = [14 41 4 16;7 12 45 0;12 12 45 17; 3 2 1 15]
b=a(:)
c=zeros(4,4)
a is a 4x4 matrix,
b is a column vector of a,
c is a 4X4 matrix of zeros.`
for kk = 1:length(b)
c(a==b(kk)) = kk;
end
c =
1 5 9 13
2 7 11 14
7 7 11 15
4 8 12 16
if I try a=magic(4), where
a =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
then
c =
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
The answer in the comments is correct - perhaps it serves a function within the program, however out of context the code does seem pretty much pointless.
This is essentially what is happening. Suppose you have a matrix A
A = [3 4;
5 6]
Then B will look like this:
B = [3 4 5 6]
C is then created by comparing the kkth element of A to the kkth element of B. If the two are equal, then the kkth element of C will be kk.
Thus, in the example above, C will look like this:
C = [1 2;
3 4]
If, as you have found out, there are multiple entries of the same number in your original matrix A, then the final matrix C will only have the index of the last unique occurence of that number. So, if
A = [3 3;
5 6]
B = [3 3 5 6]
C = [2 2;
3 4]
The reason your first C has 7 three times is because the last position of 12 is at position 7. The reason your second C is different from your first C is because the A that it was made from is totally unique.

If A is a vector subset of B, how can I find the indices of A within B in MATLAB?

Consider a row vector A and row vector B. For example:
A = [1 2 3 7 8 10 12];
B = [1 1 2 2 2 3 5 6 6 7 7 7 8 8 10 10 10 11 12 12 12 13 15 16 18 19];
A has previously been checked to be a subset of B. By subset, I specifically mean that all elements in A can be found in B. I know that elements in A will not ever repeat. However, the elements in B are free to repeat as many or as few times as they like. I checked this condition using:
is_subset = all(ismember(A,B));
With all that out of the way, I need to know the indices of the elements of A within B including the times when these elements repeat within B. For the example A and B above, the output would be:
C = [1 2 3 4 5 6 10 11 12 13 14 15 16 17 19 20 21];
Use ismember to find the relevant logical indices. Then convert them to linear indices using find.
C = find(ismember(B,A));
You can find the difference of each element of A with B, and get the indices you want. Something like below:
A = [1 2 3 7 8 10 12];
B = [1 1 2 2 2 3 5 6 6 7 7 7 8 8 10 10 10 11 12 12 12 13 15 16 18 19];
C = [1 2 3 4 5 6 10 11 12 13 14 15 16 17 19 20 21];
tol = 10^-3 ;
N = length(A) ;
iwant = cell(N,1) ;
for i = 1:N
idx = abs(A(i)-B)<=tol ;
iwant{i} = find(idx) ;
end
iwant = [iwant{:}] ;

Rearrange vector every nth column

Let's say I have a vector:
A=[1 2 3 6 7 8 11 12 13]
and I'm trying to achieve final output like:
[1 6 11 2 7 12 3 8 13]
Where the vector is rearranged to front every nth column, in this case, 3rd. Using indexing will work, but it requires a loop, which I'm trying to avoid. Any idea how to do it in a vectorized way? Thanks!
nth=3;
for i=1:nth:size(A,2)
A_(:,nth)= A(:,i:nth:end)
end
The suggestion that #jodag posted in the comments works totally fine. Alternatively, this should also do the job... but the constraint is the same, A must be divisible by nth:
nth = 3;
A = [1 2 3 6 7 8 11 12 13];
A_len = numel(A);
A_div = floor(A_len / nth);
seq = repmat(1:nth:A_len,1,A_div);
inc = sort(repmat(0:nth-1,1,A_div));
A = A(seq + inc)
Output:
A =
1 6 11 2 7 12 3 8 13

Vectorising a Matlab code to pick specific indices of a matrix

I have a matrix A in Matlab of dimension Nx(N-1), e.g.
N=5;
A=[1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16;
17 18 19 20];
I want to rearrange the elements of A in a certain way. Specifically I want to create a matrix B of dimension (N-1)xN such that:
for i=1,...,N,
B(:,i) collects
1) the first i-1 elements of the i-1th column of A and
2) the last N-i elements of the ith column of A.
Notice that for i=1 the i-1th column of A does not exist and therefore 1) is skipped; similarly, for i=N theith column of A does not exist and therefore 2) is skipped.
In the example above
B=[5 1 2 3 4
9 10 6 7 8
13 14 15 11 12
17 18 19 20 16];
This code does what I want. I am asking your help to vectorise it in an efficient way.
B=zeros(N-1,N);
for i=1:N
if i>1 && i<N
step1=A(1:i-1,i-1);
step2=A(i+1:N,i);
B(:,i)=[step1;step2];
elseif i==1
B(:,i)=A(i+1:N,i);
elseif i==N
B(:,i)=A(1:i-1,i-1);
end
end
Extract the lower and upper triangular matrices of A. Then reassemble them with a "diagonal shift":
u = triu(A);
l = tril(A,-1);
B = padarray(u(1:end-1,:),[0 1],'pre') + padarray(l(2:end,:),[0 1],'post');
Another valid approach using logical indexing combined with tril and triu:
B = zeros(size(A'));
B(tril(true(size(B)))) = A(tril(true(size(A)), -1));
B(triu(true(size(B)), 1)) = A(triu(true(size(A))));
Result:
>> B
B =
5 1 2 3 4
9 10 6 7 8
13 14 15 11 12
17 18 19 20 16

matlab: dividing vector into overlapping chunks of fixed size

I've a vector that I would like to split into overlapping subvectors of size cs in shifts of sh. Imagine the input vector is:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
given a chunksize of 4 (cs=4) and shift of 2 (sh=2), the result should look like:
[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]
note that the input vector is not necessarily divisible by the chunksize and therefore some subvectors are discarded. Is there any fast way to compute that, without the need of using e.g. a for loop?
In a related post I found how to do that but when considering non-overlapping subvectors.
You can use the function bsxfun in the following manner:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
A = v(bsxfun(#plus,(1:cs),(0:sh:length(v)-cs)'));
Here is how it works. bsxfun applies some basic functions on 2 arrays and performs some repmat-like if the sizes of inputs do not fit. In this case, I generate the indexes of the first chunk, and add the offset of each chunck. As one input is a row-vector and the other is a column-vector, the result is a matrix. Finally, when indexing a vector with a matrix, the result is a matrix, that is precisely what you expect.
And it is a one-liner, (almost) always fun :).
Do you have the signal processing toolbox? Then the command is buffer. First look at the bare output:
buffer(v, 4, 2)
ans =
0 1 3 5 7 9 11
0 2 4 6 8 10 12
1 3 5 7 9 11 13
2 4 6 8 10 12 0
That's clearly the right idea, with only a little tuning necessary to give you exactly the output you want:
[y z] = buffer(v, 4, 2, 'nodelay');
y.'
ans =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
That said, consider leaving the vectors columnwise, as that better matches most use cases. For example, the mean of each window is just mean of the matrix, as columnwise is the default.
I suppose the simplest way is actually with a loop.
A vectorizes solution can be faster, but if the result is properly preallocated the loop should perform decently as well.
v = 1:13
cs = 4;
sh = 2;
myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;
for t = cs:sh:numel(v)
count = count+1;
myMat(count,:) = v(t-cs+1:t);
end
You can accomplish this with ndgrid:
>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
The nice thing about the second syntax of the colon operator (j:i:k) is that you don't have to calculate k exactly (e.g. 1:2:6 gives [1 3 5]) if you plan to discard the extra entries, as in this problem. It automatically goes to j+m*i, where m = fix((k-j)/i);
Different test:
>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
And a new row will form with v=1:17. Does this handle all cases as needed?
What about this? First I generate the starting-indices based on cs and sh for slicing the single vectors out of the full-length vector, then I delete all indices for which idx+cs would exceed the vector length and then I'm slicing out the single sub-vectors via arrayfun and afterwards converting them into a matrix:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(#(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')
E.g. for cs=5; sh=3; this would give:
idx =
1 3 5 7
ans =
1 2 3 4 5
3 4 5 6 7
5 6 7 8 9
7 8 9 10 11
Depending on where the values cs; sh come from, you'd probably want to introduce a simple error-check so that cs > 0; as well as sh < cs. sh < 0 would be possible theoretically if you'd want to leave some values out in between.
EDIT: Fixed a very small bug, should be running for different combinations of sh and cs now.