Can't understand some array syntax - arrays

I found a MATLAB code like this one:
x = [1, ([1:(m-1)].^a)];
where a and m are scalar.
Could somebody explain that? I'm not so familiar with the MATLAB programming language.

1:(m-1) creates and array from 1 to m-1 in steps of 1.
.^a raises each element in the previous array to the power a (^ is a regular power and tries to compute the matrix power, the . makes operations element-wise, i.e. raise each element to power a instead of the whole matrix)
[1, y] is simply the array y with a 1 prepended as first element.
Putting this all together we find that x is an array which starts with 1, followed by an integer array 1:(m-1) with each element raised to the power a.
m=5;a=3;
x = [1, ([1:(m-1)].^a)]
x =
1 1 8 27 64
Broken down in steps:
tmp = 1:(m-1)
tmp =
1 2 3 4
tmp2 = tmp.^a
ans =
1 8 27 64
x = [1 tmp2]
x =
1 1 8 27 64

Related

MATLAB: Sort a 3d array by another 3d array

I have a 3d array A of random numbers which I'd like to order each k'th dimension individually:
A=rand(3,1,16);
[m, n, k]=size(A);
The array that dictates the order of each matrix in the 3rd dimension is B:
B=randi(3,3,1,16); %this should be without replacement but think it will work anyway
If A(:,1,1)=[0.5, 0.2, 0.6]' and B(:,1,1)=[3,1,2] then the ordered A should be [0.2, 0.6, 0.5]' and so on for each A(:,1,1:k). Please note it's not ordering A numerically.
A(B) is what I might have expected to work and keeps the dimensions but not the right orders.
I've tried to work through this: https://uk.mathworks.com/matlabcentral/answers/307838-sort-3d-matrix-according-to-another-3d-matrix without any success.
Any thoughts would be much appreciated.
To sort A along the k-th dimension based on B: if your data is not complex, a simple way is:
Pack A and B into a complex array where A is the imaginary part and B is the real part;
Sort along the k-th dimension based on the real part;
Keep the imaginary part.
This is done in one line as follows:
result = imag(sort(B+1j*A, k, 'ComparisonMethod', 'real'));
Example:
>> A = rand(2,4,3)
A(:,:,1) =
0.162182308193243 0.311215042044805 0.165648729499781 0.262971284540144
0.794284540683907 0.528533135506213 0.601981941401637 0.654079098476782
A(:,:,2) =
0.689214503140008 0.450541598502498 0.228976968716819 0.152378018969223
0.748151592823709 0.083821377996933 0.913337361501670 0.825816977489547
A(:,:,3) =
0.538342435260057 0.078175528753184 0.106652770180584 0.004634224134067
0.996134716626885 0.442678269775446 0.961898080855054 0.774910464711502
>> B = randi(9, size(A))
B(:,:,1) =
8 1 3 4
8 4 8 9
B(:,:,2) =
2 2 8 5
3 2 6 2
B(:,:,3) =
8 4 4 3
6 5 1 2
>> k = 2;
>> result = imag(sort(B+1j*A, k, 'ComparisonMethod', 'real'))
result(:,:,1) =
0.311215042044805 0.165648729499781 0.262971284540144 0.162182308193243
0.528533135506213 0.601981941401637 0.794284540683907 0.654079098476782
result(:,:,2) =
0.450541598502498 0.689214503140008 0.152378018969223 0.228976968716819
0.083821377996933 0.825816977489547 0.748151592823709 0.913337361501670
result(:,:,3) =
0.004634224134067 0.078175528753184 0.106652770180584 0.538342435260057
0.961898080855054 0.774910464711502 0.442678269775446 0.996134716626885

what is the matlab way without loop to multiply a matrix with a vector (extending to the 3rd dim)?

A simple example to illustrate all elements of a matrix multiplying each element of a vector to generate a 3D array.
M = reshape(1:12,4,3);
V = 1:2;
n = length(V);
A = nan([size(M),n]);
for ii = 1 : n
A(:,:,ii) = M * V(ii);
end
then
A(:,:,1) =
1 5 9
2 6 10
3 7 11
4 8 12
A(:,:,2) =
2 10 18
4 12 20
6 14 22
8 16 24
Or by repmat both M and V to the size of [4,3,2],
A = repmat(M,1,1,n) * reshape(V(ones(size(M)),:),[size(M),n])
It creates two 3D array by repmat besides the resulting 3d array A.
How to make it efficiently WITHOUT for loop and save the memory use?
According to the answer by #Lincoln,
A = bsxfun(#times, repmat(M,1,1,n), reshape(1:n, 1, 1, n));
repmat the vector V to 3d is not necessary.
Is it possible to create NO 3d array if the final result wanted is 2d, the sum of A along the 3rd dim? By for loop, the code would be
M = reshape(1:12,4,3);
V = 1:2;
n = length(V);
A = 0;
for ii = 1 : n
A = A + M * V(ii);
end
Try replacing the for.. loop with:
M_rep = repmat(M,1,1,n) %//repeat M in the 3rd dimension n times
v = reshape(1:n, 1, 1, n) %//create a vector [1 2 .. n] pointing in the third dimension
A = bsxfun(#times, M_rep, v) %//vector multiply them in the third dimension
In your above example, n=2.
EDIT (to your added question): To sum without allocating A:
B = sum(bsxfun(#times, M_rep, v),3);

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);

Vectorizing the subtraction of multiple vectors from one individual vector

I am trying to vectorize, or make the following code more efficient:
[Y,k] = min(abs(dxcp-X));
X = dxcp(k);
The objective of the code is to compare a value X to an array of accepted values for x (dxcp) and assign X to the closest value in the array dxcp. For example:
X is equal to 9 and the dxcp array is: [ 1, 2, 3, 6, 10, 20]. The second line would change X to be equal to 10.
I am trying to change my script so that X can be inputted as an array of numbers and was wondering what would be the most efficient way to go about making the above code work for this case. Of course I could use:
for i = 1:numel(X)
[Y,k] = min(abs(dxcp-X(i)));
X(i) = dxcp(k);
end
But I have the feeling that there must be a way to accomplish this more efficiently. Cheers, nzbru.
You need to use bsxfun to extend your case to a vector case.
Code
dxcp = [1 2 3 6 10 20];
X = [2 5 9 18]
abs_diff_vals = abs(bsxfun(#minus,dxcp,X')); %%//'
[~,k] = min(abs_diff_vals,[],2);
X = dxcp(k)
Output
X =
2 5 9 18
X =
2 6 10 20

loop to remove repeated elements of a vector and add corresponding elements of another vector

I am using MATLAB to write a code that multiplies polynomials. Most parts of my code work however there is one part where I have two row vectors a and b. I want to remove repeated elements of a and then add the corresponding elements of b. This is what I have written
c=length(a);
d=length(b);
remove=[];
for i=1:c
for j=i+1:c
if (a(i)==a(j))
remove=[remove,i];
b(j)=b(i)+b(j);
end
end
end
a(remove)=[];
b(remove)=[];
The problem with this is if there is an element in a that appears more than twice, it doesn't work properly.
For example if a=[5,6,8,9,6,7,9,10,8,9,11,12] and b=[1,7,1,-1,3,21,3,-3,-4,-28,-4,4]
then once this code is run a becomes [5,6,7,10,8,9,11,12] which is correct but b becomes [1,10,21,-3,-3,-27,-4,4] which is correct except the -27 should be a -26.
I know why this happens because the 9 in a(1,4) gets compared with the 9 in a(1,7) so b(1,7) becomes b(1,7)+b(1,4) and then a(1,4) gets compared with the 9 in a(1,10). and then later the a(1,7) compares with a(1,10) and so the new b(1,7) adds to the b(1,10) however the b(1,4) adds to the b(1,10) too. I somehow need to stop this once one repeated element has been found because here b(1,4) has been added twice when it should only be added once.
I am not supposed to use any built in functions, is there a way of resolving this easily?
I would prefer using built in functions, but assuming you have to stick to your own approach, you can try this:
a=[5,6,8,9,6,7,9,10,8,9,11,12];
b=[1,7,1,-1,3,21,3,-3,-4,-28,-4,4];
n = numel(a);
remove = zeros(1,n);
temp = a;
for ii = 1:n
for jj = ii+1:n
if temp(ii) == temp(jj)
temp(ii) = NaN;
remove(ii) = ii;
b(jj) = b(jj) + b(ii);
end
end
end
a(remove(remove>0)) = []
b(remove(remove>0)) = []
a =
5 6 7 10 8 9 11 12
b =
1 10 21 -3 -3 -26 -4 4
It's not much different from your approach, except for changing the iith value of a if it is found later. To avoid overwriting the values in a with NaN, I'm using a temporary variable for this.
Also, as you can see, I'm avoiding remove = [remove i], because this will create a growing vector, which is very slow.
It can be solved in a vectorized manner with the following indexing nightmare (perhaps someone will come up with a simpler approach):
a = [5,6,8,9,6,7,9,10,8,9,11,12];
b = [1,7,1,-1,3,21,3,-3,-4,-28,-4,4];
[sa, ind1] = sort(a);
[~, ii, jj] = unique(sa);
[ind2, ind3] = sort(ind1(ii));
a = a(ind2);
b = accumarray(jj(:),b(ind1)).';
b = b(ind3);
Anyway, to multiply polynomials you could use conv:
>> p1 = [1 3 0 2]; %// x^3 + 3x^2 + 1
>> p2 = [2 -1 4]; %// 2x^2 - x + 4
>> conv(p1,p2)
ans =
2 5 1 16 -2 8 %// 2x^5 + 5x^4 + x^3 + 16x^2 - 2x + 8

Resources