Define ranges for multiple values - matlab

I have two arrays
A=[1;2]
B= [5;6]
Now I want to have the matrix C = A:B such that
C = [1 2 3 4 5; 2 3 4 5 6]
How can I do this in matlab?

You can do this using arrayfun in combination with cell2mat like this:
A =
1 4 7 10
B =
5 8 11 14
cell2mat(arrayfun(#(n) (A(n):B(n)), 1:numel(A),'UniformOutput', false)')
ans =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
You can shorten it down a bit using an abbreviation for UniformOutput, but I suggest writing it out since the abbreviations might no longer be unambiguous in future MATLAB versions. Check this question for a lengthy discussion on the topic.

Your question implicitly assumes that B(1)-A(1) equals B(2)-A(2) etc; otherwise the result is undefined.
You can do it quite generally and efficiently as follows: build the first row, and then use bsxfun to obtain all other rows:
C = bsxfun(#plus, A(1):B(1), A(:)-A(1));

C = [A(1,1):B(1,1);A(2,1):B(2,1)];

Try it:
C=[ A(1):1:B(1); A(2):1:B(2) ]

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.

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

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.

Matlab - a command to sort variables into groups and output the group indices

I have a vector, for example: a = [1 1 2 2 7 7 7 10 10 10 10 11 15]. It can be unsorted, but here I'm writing it as sorted. I am looking for a Matlab command that will convert the above to [1 1 2 2 3 3 3 4 4 4 4 5 6]. Is there a good way to do this?
There's at least two ways to do this
(1) use the third output of unique:
[~,~,out] = unique(a)
(2) use grp2idx from the statistics toolbox
out = grp2idx(a)
I'm not sure if it's possible to do the conversion with only one command, but this is one way to do it:
a = [1 1 2 2 7 7 7 10 10 10 10 11 15];
a = sort(a);
UniqVector = unique(a);
for i = 1:size(UniqVector, 2)
a(a == UniqVector(i)) = i;
end

Converting a matlab matrix to a vector

I want to get a vector of elements of a Matlab matrix at predefined locations. For example, I have the following
>> i = [1,2,3];
>> j = [1,3,4];
>> A = [1,2,3,4; 5,6,7,8; 9,10,11,12; 13,14,15,16]
A =
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
I want a vector that will give me the values of A at the locations correspongin to i,j. I tried
A(i,j)
ans =
1 3 4
5 7 8
9 11 12
but this is not what I wanted. I want to get the following
>> [A(i(1),j(1)); A(i(2),j(2));A(i(3),j(3))]
ans =
1
7
12
What is the matlab syntax for that? Please, avoid suggesting for loops or anything that is not in a vectorized form, as I need this to be done fast. Hopefully there will be some built-in function.
to get it in the fastest way, use linear indexing:
A((j-1)*size(A,1)+i)
remember that MATLAB uses a column-major order.
A(sub2ind(size(A),i,j))
If you really crave speed, you might try making your own copy of sub2ind.m that strips out all the input-checking that that function does.
To understand how to do this, it is best to understand how matlab stores its arrays. In the matrix:
i = [1,2,3];
j = [1,3,4];
A = [1,2,3,4; 5,6,7,8; 9,10,11,12; 13,14,15,16]
matlab stores the elements going DOWN the columns. So they actually reside in memory in the order:
{1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16}
You can actually index a 2-d array using a SINGLE index. This is why the sub2ind trick works. Since the elements that you want to get are the 1st, 10th and 15th elements, as stored in a column-wise ordering,
singleIndex = [1 10 15];
A(singleIndex)
ans =
1 7 12
To confirm that sub2ind gave that index list, try it...
ind = sub2ind([4 4],i,j)
ind =
1 10 15
For now I'm using this:
>> diag(A(i,j))
ans =
1
7
12