I am a bit new in using Matlab, and I have a question about defining a multivariable function for vector input.
If the function is a single function, say f(t), I know how to make it for vector input. The general way is to use arrayfun after defining a f(t). How about for multivariable function, say f(x,y)? What I want to do is to get two inputs, say [1 2 3] for x and [4 5 6 7] for y (dimension may be different, but both of them are either column vector or row vector) so that I can calculate to give
[f(1,4),f(1,5),f(1,6),f(1,7);
f(2,4),f(2,5),f(2,6),f(2,7);
f(3,4),f(3,5),f(3,6),f(3,7)]
The difficulty is that the vector input for x and y may not be in the same dimension.
I understand it may be difficult to illustrate if I do not have an example of f(x,y). For my use of f(x,y), it may be very complicated to display f(x,y). For simplicity, treat f(x,y) to be x^2+y, and once defined, you cannot change it to x.^2+y for vector inputs.
Here is a set of suggestions using ndgrid:
testfun = #(x,y) x^2+y; % non-vectorized form
x = 1:3;
y = 4:7;
[X,Y] = ndgrid(x,y);
% if the function can be vectorized (fastest!):
testfun_vec = #(x,y) x.^2+y; % vectorized form
A = testfun_vec(X,Y);
% or without ndgrid (also super fast):
B = bsxfun(testfun_vec,x.',y); % use the transpose to take all combinations
% if not, or if it's not bivariate operation (slowest):
C = arrayfun(testfun,X(:),Y(:));
C = reshape(C,length(x),length(y));
% and if you want a loop:
D = zeros(length(x),length(y));
for k = 1:length(X(:))
D(k) = testfun(X(k),Y(k));
end
Which will output for all cases (A,B,C and D):
5 6 7 8
8 9 10 11
13 14 15 16
As mentioned already, if you can vectorize your function - this is the best solution, and if it has only two inputs bsxfun is also a good solution. Otherwise if you have small data and want to keep your code compact use arrayfun, if you are dealing with large arrays use an un-nested for loop.
Here is the code using for loops and inline functions:
x = [1 2 3];
y = [4 5 6 7];
f = #(x,y) x^2 +y;
A = zeros(length(x), length(y));
for m = 1:length(x)
for n = 1:length(y)
A(m, n) = f(x(m), y(n));
end
end
disp(A);
Result:
A =
5 6 7 8
8 9 10 11
13 14 15 16
>> x = [1 2 3];
>> y = [4 5 6 7];
>> outValue = foo(x, y);
>> outValue
outValue =
5 6 7 8
8 9 10 11
13 14 15 16
Make this function:
function out = foo(x, y)
for i = 1 : length(x)
for j = 1 : length(y)
out(i, j) = x(i)^2 + y(j);
end
end
Related
Consider a general vector which represent some non-linear function
for example:
x = [1 2 3 4 5 6 7 8 9 10];
f = [-1 6 8 7 5 2 0.1 -2 -3];
Is there a method in matlab that can find the solutions of f(x)=0? with some given accuracy
If you think about it, when you have a random distribution f, finding zeros can only be done with linear interpolation between the data points:
For your example, I would define a function myFunc as:
function y = myFunc(val)
x = [1 2 3 4 5 6 7 8 9 10];
f = [-1 6 8 7 5 2 0.1 -2 -3 3];
P = griddedInterpolant (x, f, 'linear', 'linear');
y = P(val);
end
and apply a root searching algorithm via something like fzero:
val = 0;
x = [1 2 3 4 5 6 7 8 9 10];
x = [-inf x inf]; % Look outside boundary too
fun = #myFunc;
sol = zeros(1, numel(x)-1);
cnt = 0;
for i = 1:length(x)-1 % fzero stops at the 1st zero hence the loop over each interval
bound = [x(i) x(i+1)];
try
z = fzero(fun, bound);
cnt = cnt+1;
sol(cnt) = z;
catch
% No answer within the boundary
end
end
sol(cnt+1:end) = [];
Maybe you can try interp1 in arrayfun like below (linear interpolation was adopted)
x0 = arrayfun(#(k) interp1(f(k:k+1),x(k:k+1),0),find(sign(f(1:end-1).*f(2:end))<0));
such that
x0 =
1.1429 7.0476 9.5000
DATA
x = [1 2 3 4 5 6 7 8 9 10];
f = [-1 6 8 7 5 2 0.1 -2 -3 3];
I've made a function that does it, but feel it is something quite "regular" that matlab must have built in answers...so if someone has any write it down and I will accept it as an answer.
function sol = find_zeros(x,f)
f_vec = round(f*10^2)/10^2;
ind=find(diff(sign(f_vec))~=0);
K = length(ind);
if (K>0)
sol = zeros(1,K);
for k=1:K
if (f_vec(ind(k))<f_vec(ind(k)+1))
df = f_vec(ind(k)):0.01:f_vec(ind(k)+1);
else
df = flip(f_vec(ind(k)+1):0.01:f_vec(ind(k)));
end
dx = linspace(x(ind(k)),x(ind(k)+1),length(df));
j = find(df==0);
sol(k) = dx(j);
end
else
sol=[];
end
sol=unique(sol);
end
Given two vectors
a = 1:3;
b = 2:4;
it's well known that the element-wise mutiplication a.*b produces
[ 2 6 12 ]
Calling that result c, we have c(i) = a(i)*b(i)
But I don't understand how a.*b', b'.*a and b'*a all produce
[ 2 4 6
3 6 9
4 8 12 ]
For the matrix multiplication b'*a, we know c(i,j) = b(i)*a(j).
But why do the other two also produce the same result?
Due to implicit expansion (introduced in 2016b) it's essentially the same as using bsxfun.
But what does that mean?
Setup:
a = 1:3;
b = 2:4;
All MATLAB versions:
c = a.*b;
% c = [2 6 12], element-wise multiplication c(j) = a(j)*b(j)
c = b'*a;
% c = [2 4 5; 3 6 9; 4 8 12]
% standard matrix multiplication of vectors
% c(i,j) = a(i) + b(j)
c = bsxfun(#times, b', a)
% c = [2 4 5; 3 6 9; 4 8 12]
% bsxfun applies the function (in this case #times) to b' and a
By definition, bsxfun "applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled". This means that singleton dimensions (dimensions whose size is 1) are expanded row-wise/column-wise to match the size of the other argument supplied to bsxfun.
So, bsxfun(#times, b', a) is equivalent to
% b' in singleton in the 2nd dimension, a is singleton in the 1st dimension
% Use repmat to perform the expansion to the correct size
repmat(b', 1, size(a,2)) .* repmat(a, size(b',1), 1)
% Equivalent to...
repmat(b', 1, 3) .* repmat(a, 3, 1)
% Equivalent to...
[2 2 2; 3 3 3; 4 4 4] .* [1 2 3; 1 2 3; 1 2 3]
% = [2 4 5; 3 6 9; 4 8 12] the same as b'*a
Before R2016b
c = a.*b'; % Error: Matrix dimensions must agree.
c = b'.*a; % Error: Matrix dimensions must agree.
Since R2016b
Newer MATLAB versions use implicit expansion, which basically means that a bsxfun equivalent is called 'under the hood' if necessary for a valid operation.
c = a.*b'; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(#times, a, b')
c = b'.*a; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(#times, b', a)
% These two are equivalent also because order of operations is irrelevant
% We can see this by thinking about the expansion discussed above
As you've noticed, this can be confusing if you don't keep track of your vector orientations! If you ever want to get a 1D output (without expansion), then you can ensure your inputs are 1D column vectors by using the colon operator like so
c = a(:).*b(:); % c = [2; 6; 12] always a column vector
The examples you listed are all element-wise multiplication.
a.*b' will give error in earlier matlab, while it performs
bsxfun(#times, a, b')
in Matlab since R2016b. This should explain the identical result for a.*b', b'.*a and b'*a.
a * b' will be matrix multiplication (inner dimension match).
I have an array of matrix m such that
m1 = [1 2;3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
m = [m1 m2 m3]
m =
1 2 2 7 9 7
3 4 8 9 8 91
I also have a vector
v = [1 2 3];
such that i want the operations between v and m result in h such that
h = [1*m1 2*m2 3*m3] = [h1 h2 h3];
I imagine I have to do this in 3-dimensional array for h, which is a 3d array. Or maybe there are better ways.
Let A be a simple 2 by 2 matrix, rand(2,2).
From h i want to extract h1 h2 and h3 out(or better not doing any extraction) and perform operations to A such that
1.
h1*A*h1'
h2*A*h2'
h3*A*h3'
and
2.
h1*h1', h2*h2', h3*h3'.
Why i want to do this in array is because i have a lot of matrix mi so I want to avoid for loop by vectorization.
From what i could understand from the question, i suppose element-wise multiplication would be better choice. You would just have to use proper concatenation and repeatation of matrices.
m1 = [1 2; 3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
% Concatenate to create 3D matrix
m = cat(3,m1,m2,m3);
v = [1 2 3];
% Create similar 3D matrix
v1 = cat(3,ones(size(m1))*v(1),ones(size(m2))*v(2),ones(size(m3))*v(3));
% Simple element wise multiplication
h = m.*v1;
% Creating a repeated 3D matrix A, repetation is along third dimension
A = repmat(rand(2,2),[1 1 3]);
% Outputs
op_1 = h.*A.*permute(h,[2 1 3]);
op_2 = h.*permute(h,[2 1 3]);
I want to define a symbolic vector in Matlab, but every element of the vector should be created through a symbolic function.
Let's say f(x)=x^2 is my function and I have a vector A=[1 2 3 4 5]. I want to create a symbolic vector so that it is going to be like this;
Symbolic_vector=[x^2 2*x^2 3*x^2 4*x^2 5*x^2]
How can I realize this ?
So far I have
A=[1 2 3 4 5];
syms x;
m = sym('m', [1 100]);
f = sym('x^2*m');
f = subs(f, m, A);
One way to do this and keep things symbolic is
A = sym('[1 2 3 a 5]');
f = #(x) x.^2;
B = f(A);
% results in B = [1 4 9 a^2 25]
You can also do directly
B = A.^2;
syms a;
A = [1 2 3 a 5];
B = A.^2;
I hope this helps.
I don't have the package for nlfilter and I didn't quite follow this example.
I have a really simple function fun and I want to apply it to a moving window of an array. The array is Nx1, and I want to look at length k intervals, say. So for N=10 and k=3 and fun = #(x) min(x); I would get
A = [13 14 2 14 10 3 5 9 15 8];
filter(A,k,fun) = [2 2 2 3 3 3 5 8];
Here I only want to look at indices 1,2,3 then 2,3,4 then ... then 8,9,10, so the final sequence is length 7. I can do this easy with a for loop, but I have no idea how to vectorize it for Matlab. Help, please. Thanks.
Here is one very simple and fast way to do it:
>> min([A(1:(end-2)); A(2:(end-1)); A(3:end)], [], 1)
ans =
2 2 2 3 3 3 5 8
EDIT: Since you want a full function...
function running_min = running_min(x, k)
xrep = repmat(x, 1, k);
xrep = reshape([xrep zeros(1, k)], length(x)+1, k);
running_min = min(xrep, [], 2)';
running_min = running_min(1:end-k);
The post you mentioned gave a general solution for building sliding windows (you could control: overlapping vs. distinct, slide step, overlap amount, windows size)
In your case, it is much simpler and can be easily performed with the HANKEL function:
x = [13 14 2 14 10 3 5 9 15 8];
idx = hankel(1:3, 3:length(x))
min( x(idx) )
If you want to build a reusable solution:
function y = myFilter(x,k,fcn)
idx = hankel(1:k, k:length(x));
y = cellfun(fcn, num2cell(x(idx),1));
end
which we use as:
x = [13 14 2 14 10 3 5 9 15 8];
y = myFilter(x, 3, #(x)min(x))
Note I am using CELLFUN in case fcn cannot operate across dimensions in a vectorized manner...