Syntax understanding in task with matlab - arrays

can comeone help to understand in MAtlab this:
k=2
n = (0:-1:-4)+k
the result; 2 1 0 -1 -2
how it works?

You are dealing with a colon operator and a vectorized sum at the same time. Let's split the problem into smaller, stand-alone problems:
In Matlab, if you add or subtract between a scalar value to a matrix, the arithmetic operation is performed on all the elements of the matrix, in a vectorized way. Example:
A = [1 2; 3 4]; % 2-by-2 matrix
S1 = A + 2 % output: S1 = [3 4; 5 6]
B = [1 2 3 4] % 1-by-5 matrix, also called column vector
S2 = B - 5 % output: S2 = [3 4 5 6]
The column operator in Matlab can be used in many situation: indexing, for iterations and vector creation. In your case, its purpose is the third one and it's syntax is START(:STEP):END. The default STEP, if not specified, is 1. The START and END parameters are never exceeded. Example:
A = 1:5 % output: A = [1 2 3 4 5]
B = -2.5:2.5:6 % output: B = [-2.5 0 2.5 5]
C = 1:-1:-5 % output: C = [1 0 -1 -2 -3 -4 -5]
D = -4:-2:0 % output: D = []
In all the programming languages, an operator precedence criterion is defined so that a one-liner calculation that uses multiple operators is atomized into smaller calculations that respect the given priority, unless parentheses are used to redefine the default criterion... just like in common maths. Example
A = 2 * 5 + 3 % output: A = 13
B = 2 * (5 + 3) % output: B = 16
Let's put all this together to provide you an explaination:
n = (0:-1:-4) + k
% vector creation has parentheses, so it's executed first
% then, the addition is executed on the result of the first operation
Let's subdivide the calculation into intermediate steps:
n_1 = 0:-1:-4 % output: n_1 = [0 -1 -2 -3 -4]
n_2 = n_1 + k % output: n_2 = [2 1 0 -1 -2]
n = n_2
Want to see what happens without parentheses?
n = 0:-1:-4+k % output: n = [0 -1 -2]
Why? Because the addition has priority over the colon operator. It's like writing n = 0:-1:(-4+k) and adding k to the END parameter of the colon operator. Let's subdivide the calculation into intermediate steps:
n_1 = -4 + k % output: n_1 = -2
n_2 = 0:-1:n_1 % output: n_2 = [0 -1 -2]
n = n_2

Basic Matlab syntax, you're dealing with range operators. There are two patterns:
[start]:[end]
and
[start]:[step]:[end]
Patterns like this result in arrays / vectors / "1D matrices".
In your example, you will get a vector first, stepping through the numbers 0 to -4 (step == -1). Then, you are adding k == 2 to all numbers in this vector.
octave:1> k = 2
k = 2
octave:2> n = (0:-1:-4)+k
n =
2 1 0 -1 -2
octave:3> 0:-1:-4
ans =
0 -1 -2 -3 -4

The parenthesizes expression determines an array. The the first number there is the first element, the second is the step and the last one is the last element. So the parenthesizes returns 0 -1 -2 -3 -4. Next we add k=2 to each element that results in 2 1 0 -1 -2

Related

Replicate scipy rankdata in matlab

I cannot figure out a clean solution on how to retrieve the new indices of the sorted array in MATLAB.
Scipy (in Python) has rankdata which I need, while MATLAB's sort provides indices.
For example [0 -3 -1 1] array after sorting in ascending order is [-3 -1 0 1].
I want to retrieve the new indices, i.e. [3 1 2 4], while MATLAB offers no built in solution..
You can use:
x = [0 -3 -1 1];
[~,ind] = sort(x);
ind = ind(ind)
unique happens to sort as well ascending, and gives indices both ways.
A = [0 -3 -1 1];
[B,I,C] = unique(A);
B =
-3 -1 0 1
C =
3
1
2
4
Do note that if A contains repetitions (unlike your example), this method will fail:
A = [0 -3 -1 1 1];
[B,I,C] = unique(A);
B =
-3 -1 0 1
C =
3
1
2
4
4
If I am interpreting what you are asking for correctly I think this should work.
x = [0 -3 -1 1];
[s,r]=sort(x);
[~,rank] = sort(r);
The output I get is
s = -3 -1 0 1
rank = 3 1 2 4

Sum up vector values till threshold, then start again

I have a vector a = [1 3 4 2 1 5 6 3 2]. Now I want to create a new vector 'b' with the cumsum of a, but after reaching a threshold, let's say 5, cumsum should reset and start again till it reaches the threshold again, so the new vector should look like this:
b = [1 4 4 2 3 5 6 3 5]
Any ideas?
You could build a sparse matrix that, when multiplied by the original vector, returns the cumulative sums. I haven't timed this solution versus others, but I strongly suspect this will be the fastest for large arrays of a.
% Original data
a = [1 3 4 2 1 5 6 3 2];
% Threshold
th = 5;
% Cumulative sum corrected by threshold
b = cumsum(a)/th;
% Group indices to be summed by checking for equality,
% rounded down, between each cumsum value and its next value. We add one to
% prevent NaNs from occuring in the next step.
c = cumsum(floor(b) ~= floor([0,b(1:end-1)]))+1;
% Build the sparse matrix, remove all values that are in the upper
% triangle.
S = tril(sparse(c.'./c == 1));
% In case you use matlab 2016a or older:
% S = tril(sparse(bsxfun(#rdivide,c.',c) == 1));
% Matrix multiplication to create o.
o = S*a.';
By normalizing the arguments of cumsum with the threshold and flooring you can get grouping indizes for accumarray, which then can do the cumsumming groupwise:
t = 5;
a = [1 3 4 2 1 5 6 3 2];
%// cumulative sum of normalized vector a
n = cumsum(a/t);
%// subs for accumarray
subs = floor( n ) + 1;
%// cumsum of every group
aout = accumarray( subs(:), (1:numel(subs)).', [], #(x) {cumsum(a(x))});
%// gather results;
b = [aout{:}]
One way is to use a loop. You create the first cumulative sum cs, and then as long as elements in cs are larger than your threshold th, you replace them with elements from the cumulative sum on the rest of the elements in a.
Because some elements in a might be larger than th, this loop will be infinite unless we also eliminate these elements too.
Here is a simple solution with a while loop:
a = [1 3 4 2 1 5 6 3 2];
th = 5;
cs = cumsum(a);
while any(cs>th & cs~=a) % if 'cs' has values larger that 'th',
% and there are any values smaller than th left in 'a'
% sum all the values in 'a' that are after 'cs' reached 'th',
% excluding values that are larger then 'th'
cs(cs>th & cs~=a) = cumsum(a(cs>th & cs~=a));
end
Calculate the cumulative sum and replace the indices value obeying your condition.
a = [1 3 4 2 1 5 6 3 2] ;
b = [1 4 4 2 3 5 6 3 5] ;
iwant = a ;
a_sum = cumsum(a) ;
iwant(a_sum<5) = a_sum(a_sum<5) ;

MATLAB Vector of elements x(i) or y(i) with max(abs(x),abs(y))

Sorry for the title, couldn't think of a concise way to phrase the problem. I need to write a MATLAB one-liner that gives you a vector of elements z(i) where z(i) is the element x(i) or y(i) given by max(abs(x(i)),abs(y(i))). I.e, z is the vector whose elements are the ith elements of x or y which has the maximum absolute value.
I have
max(abs(x),abs(y))
But this obviously gives you a vector of the greatest absolute values. This is close to what I want, but I need to get the sign back of the original vector. I'm not sure how to do this on a single line.
Under the assumption that x and y are arrays (not necessarily vectors) of identical dimensions, you can use logical indexing:
(abs(x)>=abs(y)).*x + (abs(x)<abs(y)).*y
For information, abs(x)>=abs(y) is a logical array for which, for all valid indices, the kth component is
1 if x(k) is greater than or equal to y(k),
0 otherwise.
Example:
>> x = [4;7;-1;9;6];
>> y = [5;2;-3;9;3];
>> (abs(x)>=abs(y)).*x + (abs(x)<abs(y)).*y
ans =
5
7
-3
9
6
If you are interested in a generic code that you could use when working with a number of 2D matrices, let's say x, y and p, you can try this -
x = [-2 4 1;
4 -3 2]
y = [8 -3 -5;
-9 1 5]
p = [6 8 6;
7 -1 -2]
mats = cat(3,x,y,p);%// concatenate all identically sized 2D matrices into 3D
[m,n] = size(x);%// get size
[maxval,dim3ind] = max(abs(mats),[],3);%// Max abs values and indices across dim3
mats_sign = sign(mats); %// signum values
out = mats_sign((dim3ind-1)*m*n + bsxfun(#plus,[1:m]',[0:n-1]*m)).*maxval %// output
Output -
x =
-2 4 1
4 -3 2
y =
8 -3 -5
-9 1 5
p =
6 8 6
7 -1 -2
out =
8 8 6
-9 -3 5
So, if you would like to include one more 2D matrix say q into the mix, just edit the first line of code -
mats = cat(3,x,y,p,q);

Create all possible Mx1 vectors from an Nx1 vector in MATLAB

I am trying to create all possible 1xM vectors (word) from a 1xN vector (alphabet) in MATLAB. N is > M. For example, I want to create all possible 2x1 "words" from a 4x1 "alphabet" alphabet = [1 2 3 4];
I expect a result like:
[1 1]
[1 2]
[1 3]
[1 4]
[2 1]
[2 2]
...
I want to make M an input to my routine and I do not know it beforehand. Otherwise, I could easily do this using nested for-loops. Anyway to do this?
Try
[d1 d2] = ndgrid(alphabet);
[d2(:) d1(:)]
To parameterize on M:
d = cell(M, 1);
[d{:}] = ndgrid(alphabet);
for i = 1:M
d{i} = d{i}(:);
end
[d{end:-1:1}]
In general, and in languages that don't have ndgrid in their library, the way to parameterize for-loop nesting is using recursion.
[result] = function cartesian(alphabet, M)
if M <= 1
result = alphabet;
else
recursed = cartesian(alphabet, M-1)
N = size(recursed,1);
result = zeros(M, N * numel(alphabet));
for i=1:numel(alphabet)
result(1,1+(i-1)*N:i*N) = alphabet(i);
result(2:M,1+(i-1)*N:i*N) = recursed; % in MATLAB, this line can be vectorized with repmat... but in MATLAB you'd use ndgrid anyway
end
end
end
To get all k-letter combinations from an arbitrary alphabet, use
n = length(alphabet);
aux = dec2base(0:n^k-1,n)
aux2 = aux-'A';
ind = aux2<0;
aux2(ind) = aux(ind)-'0'
aux2(~ind) = aux2(~ind)+10;
words = alphabet(aux2+1)
The alphabet may consist of up to 36 elements (as per dec2base). Those elements may be numbers or characters.
How this works:
The numbers 0, 1, ... , n^k-1 when expressed in base n give all groups of k numbers taken from 0,...,n-1. dec2base does the conversion to base n, but gives the result in form of strings, so need to convert to the corresponding number (that's part with aux and aux2). We then add 1 to make the numbers 1,..., n. Finally, we index alphabet with that to use the real letters of numbers of the alphabet.
Example with letters:
>> alphabet = 'abc';
>> k = 2;
>> words
words =
aa
ab
ac
ba
bb
bc
ca
cb
cc
Example with numbers:
>> alphabet = [1 3 5 7];
>> k = 2;
>> words
words =
1 1
1 3
1 5
1 7
3 1
3 3
3 5
3 7
5 1
5 3
5 5
5 7
7 1
7 3
7 5
7 7
use ndgrid function in Matlab
[a,b] = ndgrid(alphabet)

How to remove elements of one array from another?

I have two arrays:
A=[1 1 2 2 3 3 3];
B=[1 3];
Is there any function that can remove elements which are contained in B from A?
The result should be
C=[1 2 2 3 3];
The order is not important, but if there is more specific elements like two times 1 in A, then I need operation that removes (from A) only as many of these specific elements is in B (in this case only one of 1 and one of 3; meaning other 1 and 3 should remain in final product C). This function should be analogous to setdiff, with the difference that it should take care of multiple instances of array elements. This analogy can hold because my B only contains elements that are in A.
For loop solution:
C = A;
for ii = 1:length(B)
C(find(C == B(ii), 1,'first')) = [];
end
Result
C =
1 2 2 3 3
Here's a vectorized solution using accumarray and repelem:
maxValue = max([A B]);
counts = accumarray(A(:), 1, [maxValue 1])-accumarray(B(:), 1, [maxValue 1]);
C = repelem(1:maxValue, max(counts, 0));
And the result for your sample data A = [1 1 2 2 3 3 3]; B = [1 3];:
C =
1 2 2 3 3
This will even work for cases where there are values in B not in A (like B = [1 4];) or more of a given value in B than in A (like B = [1 1 1];).
Note: The above works sinceA and B contain integers. If they were to contain floating-point values, you could map the unique values to integers first using unique and ismember. Let's say we had the following sample data:
A = [0 0 pi pi 2*pi 2*pi 2*pi];
B = [0 2*pi];
Here's a variant of the above code that can handle this:
uniqueValues = unique([A B]);
[~, A] = ismember(A, uniqueValues);
[~, B] = ismember(B, uniqueValues);
maxValue = max([A B]);
counts = accumarray(A(:), 1, [maxValue 1])-accumarray(B(:), 1, [maxValue 1]);
C = uniqueValues(repelem(1:maxValue, max(counts, 0)));
And the results:
C =
0 3.1416 3.1416 6.2832 6.2832 % [0 pi pi 2*pi 2*pi]

Resources