Extraction of components in vector function in MATLAB - matlab

I have a code segment as follows:
f = #(x) [x(1)^2 ; x(2)^2]
X = [2; 3]
When I type f(X), I simply obtain the following:
f(X)
ans =
4
9
Now, think that there is a for loop going from 1 to 2. According to value of loop, I want to extract the row which is the value of loop. For instance:
for i=1:2
when i=1 it will extract 1st element, which is: 4
when i=2 it will extract 2nd element, which is: 9
end
I did this by the following:
for i=1:2
X1 = f(X)
Result = X1(i)
end
This works perfectly well. However, I do not want to define such intermediate variables. Is it possible directly to extract the certain row of the function?
Another way of doing is is to create a unit vector and multiply the function itself, but I do not want this as well. What I mean is the following:
when i=1; unit = [1 0]
[1 0]*[2;4] = 2
when i=2; unit = [0 1]
[0 1]*[2;4] = 4
This also works well but I do not want this.
I just want to call directly f(X) but give me the row desired.
Thanks in advance!

You are defining your function as :
f = #(x) [x(1)^2 ; x(2)^2]
If you give x as a column vector, it would read row-wise.
Thus, your row-indexing method of i=1,2 won't work, because the function would need first and second row with x(1) and x(2) at the same time.
I think, the best you can do is this -
X1 = f(X)
for i=1:2
X1(i)
end
The best practice to solve your problem and still access each output from using the function on each element of X would be something like this -
f = #(x) x.^2;
X = [2 3];
X1 = f(X);
for i=1:numel(X)
Result = X1(i);
%// Do something with Result
end
Edit 1
f = #(x) x.^2;
X = [2 3];
for i=1:numel(X)
Result = f(X(i)) %%// Instead of f(X,1) you need f(X(1)) and so on..
%// Do something with Result
end

Here's another possible way of doing it:
f = #(x,n) [x(n).^2];
Where n is the indices of x you want returned.
x = [3 5];
f(x,1:2)
ans =
9 25
or
f(x,2)
ans =
25

Related

Newton–Raphson method with vector inputs in MATLAB

For this problem, we need to make use of the Newton-Raphson method to locate the roots of a particular function.
The code works for when the input is a single value, yet when the input is a vector, the answers aren't quite right.
For example, when x=2 is an input, the value 2.5933 is returned and when x=4, 4.3215 is returned. Both these answers are correct, yet when I enter the vector x = [2,4], it returns [2.4106,4.4106].
f = #(x) [(17/77196).*x.^(3)-(15/12866).*x.^(2)+0.004];
fd = #(x) [(17/25732).*x.^(2)-(15/6433).*x];
x= %initial guess;
for i=1:10
x=x-f(x)/fd(x);
end
You can try this
f = #(x) [(17/77196).*x.^(3)-(15/12866).*x.^(2)+0.004];
fd = #(x) [(17/25732).*x.^(2)-(15/6433).*x];
x= [2, 4];
for i = 1:10
x = x - f(x)./fd(x);
end
x
You were missing . after f(x) to make it an element-wise division.

Matlab How to iterate a function through a list

I need some help iterating over a function that depends on two variables.
So let's say I have a function that depends on two variables.
Let's call it f = x + y
Now, I have a two lists, one of x variables and one of y variables. For example,
xlist = [1 2 3] and
ylist = [4 5 6]
And I want to go through each element of the lists and plug it into f. For example, set x=1 and then evaluate f for y=4, then y=5, then y=6... and repeat for x=2 and x=3.
Finally, I want to return a matrix of the calculated values. For the example above, the answer should be
[5 6 7];[6 7 8];[7 8 9]
How would I go about doing this?
Assuming the function can't be vectorized and thus you really need to iterate, a simple way is via ndgrid (to create x, y values that describe all possible pairs) and arrayfun (to iterate over the two x, y values at the same time):
f = #(x,y) x+y; % Or f = #fun, if fun is a function defined elsewhere
xlist = [1 2 3];
ylist = [4 5 6];
[xx, yy] = ndgrid(xlist, ylist); % all pairs
result = arrayfun(f, xx, yy);
In many cases the function can be vectorized, which results in faster code. For the example function this would be done defining f as
f = #(x,y) bsxfun(#plus, x(:), y(:).');
or in recent Matlab versions you can exploit implicit singleton expansion and just write
f = #(x,y) x(:)+y(:).';
In either case, note that the two arguments of addition are forced to be a column vector (x(:)) and a row vector (y(:).'), so that singleton expansion will automatically create all pairs:
xlist = [1 2 3];
ylist = [4 5 6];
result = f(xlist, ylist);
Another way to do it would be to use two for loops:
x_values=[2,4,6,8];
y_values=[1,3,5,7];
%initialize a matrix with zeros
output_matrix=zeros(length(x_values),length(y_values));
for i=1:length(x_values)
for j=1:length(y_values)
output_matrix(i,j)=x_values(i)+y_values(j);
end
end
output_matrix

Obtain 3-D matrix from multiplication of one 1-D matrix and one 2-D matrix [duplicate]

As always trying to learn more from you, I was hoping I could receive some help with the following code.
I need to accomplish the following:
1) I have a vector:
x = [1 2 3 4 5 6 7 8 9 10 11 12]
2) and a matrix:
A =[11 14 1
5 8 18
10 8 19
13 20 16]
I need to be able to multiply each value from x with every value of A, this means:
new_matrix = [1* A
2* A
3* A
...
12* A]
This will give me this new_matrix of size (12*m x n) assuming A (mxn). And in this case (12*4x3)
How can I do this using bsxfun from matlab? and, would this method be faster than a for-loop?
Regarding my for-loop, I need some help here as well... I am not able to storage each "new_matrix" as the loop runs :(
for i=x
new_matrix = A.*x(i)
end
Thanks in advance!!
EDIT: After the solutions where given
First solution
clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
val = bsxfun(#times,A,permute(x,[3 1 2]));
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
toc
Output:
Elapsed time is 7.597939 seconds.
Second solution
clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
Ps = kron(x.',A);
toc
Output:
Elapsed time is 48.445417 seconds.
Send x to the third dimension, so that singleton expansion would come into effect when bsxfun is used for multiplication with A, extending the product result to the third dimension. Then, perform the bsxfun multiplication -
val = bsxfun(#times,A,permute(x,[3 1 2]))
Now, val is a 3D matrix and the desired output is expected to be a 2D matrix concatenated along the columns through the third dimension. This is achieved below -
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[])
Hope that made sense! Spread the bsxfun word around! woo!! :)
The kron function does exactly that:
kron(x.',A)
Here is my benchmark of the methods mentioned so far, along with a few additions of my own:
function [t,v] = testMatMult()
% data
%{
x = [1 2 3 4 5 6 7 8 9 10 11 12];
A = [11 14 1; 5 8 18; 10 8 19; 13 20 16];
%}
x = 1:50;
A = randi(100, [1000,1000]);
% functions to test
fcns = {
#() func1_repmat(A,x)
#() func2_bsxfun_3rd_dim(A,x)
#() func2_forloop_3rd_dim(A,x)
#() func3_kron(A,x)
#() func4_forloop_matrix(A,x)
#() func5_forloop_cell(A,x)
#() func6_arrayfun(A,x)
};
% timeit
t = cellfun(#timeit, fcns, 'UniformOutput',true);
% check results
v = cellfun(#feval, fcns, 'UniformOutput',false);
isequal(v{:})
%for i=2:numel(v), assert(norm(v{1}-v{2}) < 1e-9), end
end
% Amro
function B = func1_repmat(A,x)
B = repmat(x, size(A,1), 1);
B = bsxfun(#times, B(:), repmat(A,numel(x),1));
end
% Divakar
function B = func2_bsxfun_3rd_dim(A,x)
B = bsxfun(#times, A, permute(x, [3 1 2]));
B = reshape(permute(B, [1 3 2]), [], size(A,2));
end
% Vissenbot
function B = func2_forloop_3rd_dim(A,x)
B = zeros([size(A) numel(x)], 'like',A);
for i=1:numel(x)
B(:,:,i) = x(i) .* A;
end
B = reshape(permute(B, [1 3 2]), [], size(A,2));
end
% Luis Mendo
function B = func3_kron(A,x)
B = kron(x(:), A);
end
% SergioHaram & TheMinion
function B = func4_forloop_matrix(A,x)
[m,n] = size(A);
p = numel(x);
B = zeros(m*p,n, 'like',A);
for i=1:numel(x)
B((i-1)*m+1:i*m,:) = x(i) .* A;
end
end
% Amro
function B = func5_forloop_cell(A,x)
B = cell(numel(x),1);
for i=1:numel(x)
B{i} = x(i) .* A;
end
B = cell2mat(B);
%B = vertcat(B{:});
end
% Amro
function B = func6_arrayfun(A,x)
B = cell2mat(arrayfun(#(xx) xx.*A, x(:), 'UniformOutput',false));
end
The results on my machine:
>> t
t =
0.1650 %# repmat (Amro)
0.2915 %# bsxfun in the 3rd dimension (Divakar)
0.4200 %# for-loop in the 3rd dim (Vissenbot)
0.1284 %# kron (Luis Mendo)
0.2997 %# for-loop with indexing (SergioHaram & TheMinion)
0.5160 %# for-loop with cell array (Amro)
0.4854 %# arrayfun (Amro)
(Those timings can slightly change between different runs, but this should give us an idea how the methods compare)
Note that some of these methods are going to cause out-of-memory errors for larger inputs (for example my solution based on repmat can easily run out of memory). Others will get significantly slower for larger sizes but won't error due to exhausted memory (the kron solution for instance).
I think that the bsxfun method func2_bsxfun_3rd_dim or the straightforward for-loop func4_forloop_matrix (thanks to MATLAB JIT) are the best solutions in this case.
Of course you can change the above benchmark parameters (size of x and A) and draw your own conclusions :)
Just to add an alternative, you maybe can use cellfun to achieve what you want. Here's an example (slightly modified from yours):
x = randi(2, 5, 3)-1;
a = randi(3,3);
%// bsxfun 3D (As implemented in the accepted solution)
val = bsxfun(#and, a, permute(x', [3 1 2])); %//'
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
%// cellfun (My solution)
val2 = cellfun(#(z) bsxfun(#and, a, z), num2cell(x, 2), 'UniformOutput', false);
out2 = cell2mat(val2); % or use cat(3, val2{:}) to get a 3D matrix equivalent to val and then permute/reshape like for out
%// compare
disp(nnz(out ~= out2));
Both give the same exact result.
For more infos and tricks using cellfun, see: http://matlabgeeks.com/tips-tutorials/computation-using-cellfun/
And also this: https://stackoverflow.com/a/1746422/1121352
If your vector x is of lenght = 12 and your matrix of size 3x4, I don't think that using one or the other would change much in term of time. If you are working with higher size matrix and vector, now that might become an issue.
So first of all, we want to multiply a vector with a matrix. In the for-loop method, that would give something like that :
s = size(A);
new_matrix(s(1),s(2),numel(x)) = zeros; %This is for pre-allocating. If you have a big vector or matrix, this will help a lot time efficiently.
for i = 1:numel(x)
new_matrix(:,:,i)= A.*x(i)
end
This will give you 3D matrix, with each 3rd dimension being a result of your multiplication. If this is not what you are looking for, I'll be adding another solution which might be more time efficient with bigger matrixes and vectors.

Getting the N-dimensional product of vectors

I am trying to write code to get the 'N-dimensional product' of vectors. So for example, if I have 2 vectors of length L, x & y, then the '2-dimensional product' is simply the regular vector product, R=x*y', so that each entry of R, R(i,j) is the product of the i'th element of x and the j'th element of y, aka R(i,j)=x(i)*y(j).
The problem is how to elegantly generalize this in matlab for arbitrary dimensions. This is I had 3 vectors, x,y,z, I want the 3 dimensional array, R, such that R(i,j,k)=x(i)*y(j)*z(k).
Same thing for 4 vectors, x1,x2,x3,x4: R(i1,i2,i3,i4)=x1(i1)*x2(i2)*x3(i3)*x4(i4), etc...
Also, I do NOT know the number of dimensions beforehand. The code must be able to handle an arbitrary number of input vectors, and the number of input vectors corresponds to the dimensionality of the final answer.
Is there any easy matlab trick to do this and avoid going through each element of R specifically?
Thanks!
I think by "regular vector product" you mean outer product.
In any case, you can use the ndgrid function. I like this more than using bsxfun as it's a little more straightforward.
% make some vectors
w = 1:10;
x = w+1;
y = x+1;
z = y+1;
vecs = {w,x,y,z};
nvecs = length(vecs);
[grids{1:nvecs}] = ndgrid(vecs{:});
R = grids{1};
for i=2:nvecs
R = R .* grids{i};
end;
% Check results
for i=1:10
for j=1:10
for k=1:10
for l=1:10
V(i,j,k,l) = R(i,j,k,l) == w(i)*x(j)*y(k)*z(l);
end;
end;
end;
end;
all(V(:))
ans = 1
The built-in function bsxfun is a fast utility that should be able to help. It is designed to perform 2 input functions on a per-element basis for two inputs with mismatching dimensions. Singletons dimensions are expanded, and non-singleton dimensions need to match. (It sounds confusing, but once grok'd it useful in many ways.)
As I understand your problem, you can adjust the dimension shape of each vector to define the dimension that it should be defined across. Then use nested bsxfun calls to perform the multiplication.
Example code follows:
%Some inputs, N-by-1 vectors
x = [1; 3; 9];
y = [1; 2; 4];
z = [1; 5];
%The computation you describe, using nested BSXFUN calls
bsxfun(#times, bsxfun(#times, ... %Nested BSX fun calls, 1 per dimension
x, ... % First argument, in dimension 1
permute(y,2:-1:1) ) , ... % Second argument, permuited to dimension 2
permute(z,3:-1:1) ) % Third argument, permuted to dimension 3
%Result
% ans(:,:,1) =
% 1 2 4
% 3 6 12
% 9 18 36
% ans(:,:,2) =
% 5 10 20
% 15 30 60
% 45 90 180
To handle an arbitrary number of dimensions, this can be expanded using a recursive or loop construct. The loop would look something like this:
allInputs = {[1; 3; 9], [1; 2; 4], [1; 5]};
accumulatedResult = allInputs {1};
for ix = 2:length(allInputs)
accumulatedResult = bsxfun(#times, ...
accumulatedResult, ...
permute(allInputs{ix},ix:-1:1));
end

Within a function, how do I create variables that will accept 2 equally sized matrices and a scalar?

function[f] = get_f(y,Q,L)
Q = zeros(2) % creating a 2x2 matrix of zeros
L = diag(zeros(2)) % creating a diagonal matrix
% still playing with how I can pull y in as a scalar, I'm thinking I have
% to assign it earlier in the script where I call this function.
f = expm((Q-L).^y).*L % execution of the function itself
How do I tell the function to look for an entered scalar, and 2 equally sized matrices, then execute the listed command?
In your function, y is whatever you put as the first argument in your function call.
For instance:
get_f(3.14, [1 2; 3 4], [1 0; 0 1])
calls the function get_f with
y = 3.14
Q = [1 2; 3 4]
L = [1 0; 0 1]
so your function will work.
However, if you want your function to fail if y is not a scalar or if Q and L don't have the same size, you can add a condition like this at the beginning of your function:
if ~isscalar(y)
error('y must be a scalar')
end
if any(size(Q) ~= size(L))
error('Q and L must have the same size')
end