In MATLAB, is there a way to rotate the elements of a array to another dimension, like:
y=[-1,0,1] --> y=[-1; 0; 1] (like transpose)
y=[-1,0,1] --> y(:,:,1)=-1, y(:,:,2)=0, y(:,:,3)=1
y=[-1,0,1] --> y(:,:,1,1)=-1, y(:,:,1,2)=0, y(:,:,1,3)=1
I would like to avoid for loops.
You can do these sorts of matrix operations using transposition, the function RESHAPE, or the function PERMUTE. For example:
y = [-1 0 1]; %# Your 1-by-3 sample array
y2 = y.'; %'# Transposing y gives you a 3-by-1 array
y2 = reshape(y,[3 1]); %# This also gives you a 3-by-1 array
y2 = permute(y,[2 1]); %# This also gives you a 3-by-1 array
y3 = reshape(y,[1 1 3]); %# This gives you a 1-by-1-by-3 array
y3 = permute(y,[3 1 2]); %# This also gives you a 1-by-1-by-3 array
y4 = reshape(y,[1 1 1 3]); %# This gives you a 1-by-1-by-1-by-3 array
y4 = permute(y,[4 1 2 3]); %# This also gives you a 1-by-1-by-1-by-3 array
While reshape and permute are more powerful tools, you can solve the given example quite easy with:
y = [-1 0 1];
y2(:,1)=y;
y3(1,1,:)=y;
y4(1,1,1,:)=y;
Related
Suppose I have a vector B = [1; 2; 3]. Then
B*B' = [1*1 1*2 1*3 ; 2*1 2*2 2*3 ; 3*1 3*2 3*3]
Now, I need to multiply the new matrix B*B' again with B, in order to get the following 3 dimensional matrix C:
C(:,:,1) = [1*1*1 1*2*1 1*3*1 ; 2*1*1 2*2*1 2*3*1 ; 3*1*1 3*2*1 3*3*1]
C(:,:,2) = [1*1*2 1*2*2 1*3*2 ; 2*1*2 2*2*2 2*3*2 ; 3*1*2 3*2*2 3*3*2]
C(:,:,3) = [1*1*3 1*2*3 1*3*3 ; 2*1*3 2*2*3 2*3*3 ; 3*1*3 3*2*3 3*3*3]
Any ideas how can I do that?
(My original vector is long so I can not do this manually..)
Before R2016b:
C = bsxfun(#times, permute(B, [3 2 1]), B*B');
After R2016b:
C = permute(B, [3 2 1]) .* (B*B');
You can use bsxfun to perform these operations.
out = bsxfun(#times, bsxfun(#times, B, B.'), reshape(B, 1, 1, []));
Or if you want to make it more legible, you can break it out into two operations. First perform the first multiplication.
tmp = bsxfun(#times, B, B.');
Then multiply this by B again (but we reshape B to be 1 x 1 x 3 to make the result a 3D matrix)
out = bsxfun(#times, reshape(B, 1, 1, []));
If you're on R2016b or later, you can just do the following.
out = (B .* B.') .* reshape(B, 1, 1, []);
Another form is to reshape the result of the first matrix multiplication into a column, perform a second matrix multiplication, and reshape the result:
C = reshape(B*reshape(B*B.',1,[]),numel(B)*[1 1 1]);
Here is what i want to do:
I have 4 inputs x1, x2, x3, x4
They each have a range of possible values, f.e
x1={1,2}
x2=x3=x4={1,2,3}
These values x1, x2, x3, x4 may be known, but they can also be unknow (input=0). I want to generate a matrix with all possible combinations.
So for example:
the input (0,0,2,3) means, that x1 and x2 are unknown and x3 and x4 are known. Since x1 has 2 possibilities and x2 has 3 possibilities I need 2*3=6 combinations, where x3 and x4 are fixed:
1 1 2 3
1 2 2 3
1 3 2 3
2 1 2 3
2 2 2 3
2 3 2 3
How do i archieve that? Normally i would do a couple nested for loops, but that doenst work, since i dont know which variables are known and which one are not. On the other hand perm() doenst really help either.
You can pre-generate all of the possible combinations of values for [x1 x2 x3 x4] and store it in the variable, for example comb.
From there on:
inputs = [x1 x2 x3 x4]; % Put your inputs in a vector
fixed = ~(inputs == 0); % Logical vector for where inputs is not zero
select = ismember(combs(:,fixed),inputs(fixed),'rows') % find where the values correspond
yourMatrix = combs(select,:); % Get your results
Try this (this should be generalisable):
% This is your input
ranges = {[1, 2], [1, 2, 3], [1, 2, 3], [1, 2, 3]};
input_v = [0, 0, 2, 3];
% initialise a cell to hold vectors to be combined
combine_us = cell(size(ranges));
for ii = 1:length(input_v)
% this tests for 0. If your arrays can contain 0, use NaN instead
if input_v(ii) == 0
combine_us{ii} = ranges{ii};
else
combine_us{ii} = input_v(ii);
end
end
% calculate the numbers of combinations added with every input
n_combinations = [1 cumprod(cellfun(#numel, combine_us))];
% initialize output matrix
out_v = zeros(n_combinations(end), length(input_v));
% set the output values, cycling so that each combination will be obtained
for ii = 1:length(input_v)
for jj = 1:n_combinations(end)
out_v(jj, ii) = combine_us{ii}(mod(ceil(jj / n_combinations(ii)) - 1, length(combine_us{ii} )) + 1);
end
end
I'm assuming your inputs are numeric vectors, rather than cell arrays of numbers. If they are really cell arrays of numbers, you can convert to numeric vectors with x1 = [x1{:}]; etc.
You can proceed as follows:
Build a cell array such that each cell contains either a whole input vector or a specific value thereof, according to s. This is easily done with a for loop, or with arrayfun.
Apply one of these answers to generate all combinations.
Code:
%// Inputs
x1 = [1,2];
x2 = [1,2,3];
x3 = [1,2,3];
x4 = [1,2,3];
s = [0 0 2 3];
%// Step 1
x = {x1 x2 x3 x4};
ind = s~=0;
x(ind) = arrayfun(#(y,t) {y{1}(t)}, x(ind), s(ind));
%// Step 2
n = numel(x);
combs = cell(1,n);
[combs{end:-1:1}] = ndgrid(x{end:-1:1});
combs = cat(n+1, combs{:});
combs = reshape(combs,[],n);
I am trying to build the following function in a three dimensional domain.
where is a constant vector, is the position vector, is a constant, and is time.
is a vector of size [1 3], is the array of size [NX*NY*NZ 3] that represents the points in the three-dimensional domain, is constant, and is array of size [1 NT].
The following is the setup of the problem.
dx = 0.1;
dy = 0.5;
dz = 0.1;
[x, y, z] = meshgrid( (1:100)*dx, (1:100)*dy, (1:100)*dz );
X = [x(:) y(:) z(:)];
k = [1 2 3];
c = 0.5;
t = 0:0.1:1;
In fact, the following loop works but it is very slow (~200 seconds).
f = zeros(numel(X)/3, numel(t));
for n = 1:numel(t)
for i = 1:numel(X)/3
f(i, n) = tan(dot(k, X(i,:)+c*t(n)));
end
end
I thought about using arrayfun and repeating the vector k using repmat and dot it with X in the second dimension but I don't know what I should do for the multiplication of c and t.
What would be an efficient way of defining the function for all the points and all the times? The output of this function, for example, looks like an array of size [NX*NY*NZ NT].
bsxfun approach to speedup f calculation -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t2 = permute(k(ones(numel(t),1),:),[3 2 1]);
t3 = bsxfun(#times,t1,t2);
f = tan(squeeze(sum(t3,2)));
Or a slight variant -
t1 = bsxfun(#plus,X,permute(c*t,[1 3 2]));
t3 = bsxfun(#times,t1,k);
f = tan(squeeze(sum(t3,2)));
f = tan(sum(bsxfun(#times, permute(k, [1 3 2]), bsxfun(#plus, permute(X, [1 3 2]), c*t)), 3));
Or replace the outer bsxfun by matrix multiplication. This seems to be slightly faster:
f = tan(reshape(reshape(bsxfun(#plus, permute(X, [1 3 2]), c*t), [], 3) * k(:), [size(X,1) numel(t)]));
I want to assemble a matrix from 5 vectors using a for loop in Matlab.
How can I do that? Or is there a simple alternative to do the same?
Here's an example: I have 5 vectors:
A = [1 2 3]
B = [1 2 3]
C = [1 2 3]
D = [1 2 3]
E = [1 2 3]
I want to create a matrix Z of size 3 x 5 from these vectors.
for loops are generally a bad idea in Matlab. Use vectorized syntax:
Z = [A;B;C;D;E]'; %'// vertical concatenation (5x3), then transpose to get 3x5
>> size(Z)
ans =
3 5
You can also transpose the vectors first and then concatenate them:
Z = [A' B' C' D' E']; %'// this comment is a syntax highlighting hotfix
>> size(Z)
ans =
3 5
If you really insist on using a for loop, here's how you would do that:
Z(3,5) = 0; %// preallocate a 3x5 numerical matrix
for i=1:3
Z(i,1) = A(i);
Z(i,2) = B(i);
Z(i,3) = C(i);
Z(i,4) = D(i);
Z(i,5) = E(i);
end
But it really makes no sense at all to do it this way...
If I have data in a 1-D vector (Y) in matlab, I can access the last value by calling 'end', such as answer = Y(end). However, in my code, I am using a cell array to store a list of vectors of various lengths. Each vector is one cell in a 1D cell array. Is there some way in matlab to reference the last value of the vector stored in a specific cell array?
You can do this by writing y{k}(end) to grab the end of the kth item. Like this:
% Make some random vectors:
y1 = [ 1 2 3];
y2 = [ 1 5 9 12];
y3 = [9 48 2 1];
% create a cell array of them:
x = {y1, y2, y3};
% grab the end of the second vector:
k = 2;
x{k}(end)