matlabFunction() is a function that can convert symbolic to anonymous function. But how to specify what input arguments to be appeared on the anonymous function?
For example,
x = sym('x', [3, 1])
func = matlabFunction(x)
It returns a handle with:
func =
function_handle with value:
#(x1,x2,x3)[x1;x2;x3]
But how to make this to be returned:?
#(x) [x(1); x(2); x(3)]
that the whole x is the input arguments, not every element of it. This could be extremely useful when x has very long colums.
Instead of making that anonymous function, you can input the elements of x as a comma separated list to func by first converting x to a cell array.
xcell = num2cell(x);
func(xcell{:})
Related
How can I access both arguments of ismember when it is used inside splitapply?
slitapply only returns scalar values for each group, so in order to compute nonscalar values for each group (as returned by the first argument of ismemebr), one has to enclose the anonymous function (in this case ismember) inside curly brackets {} to return a cell array.
But now, when I provide two output arguments to splitapply, I get an error:
Output argument "varargout{2}" (and maybe others) not assigned during call to
"#(x,y) {ismember(x,y)}"
ADD 1
I can create another function, say, ismember2cell which would apply ismember and turn outputs into cell arrays:
function [a, b] = ismember2cell(x,y)
[a,b] = ismember(x,y);
a = {a};
b = {b};
end
but maybe there is a solution which doesn't require this workaround.
One potentially faster option is to just do what splitapply is already doing under the hood by splitting your data into cell arrays (using functions like mat2cell or accumarray) and then using cellfun to apply your function across them. Using cellfun will allow you to easily capture multiple outputs (such as from ismember). For example:
% Sample data:
A = [1 2 3 4 5];
B = [1 2 1 5 5];
G = [1 1 1 2 2]; % Group index
% Group data into cell arrays:
cellA = accumarray(G(:), A(:), [], #(x) {x(:).'}); % See note below about (:).' syntax
cellB = accumarray(G(:), B(:), [], #(x) {x(:).'});
% Apply function:
[Lia, Locb] = cellfun(#ismember, cellA, cellB, 'UniformOutput', false);
NOTE: My sample data are row vectors, but I had to use the colon operator to reshape them into column vectors when passing them to accumarray (it wants columns). Once distributed into a cell array, each piece of the vector would still be a column vector, and I simply wanted to keep them as row vectors to match the original sample data. The syntax (:).' is a colon reshaping followed by a nonconjugate transpose, ensuring a row vector as a result no matter the shape of x. In this case I probably could have just used .', but I've gotten into the habit of never assuming what the shape of a variable is.
I cannot find a global solution, but the accepted answer of this post helps me to define a helper function for your problem:
function varargout = out2cell(varargin)
[x{1:nargout}]=feval(varargin{:});
varargout = num2cell(x);
I think that you may succeed in calling
splitapply(#(x,y) out2cell(#ismember, x, y), A, B);
I am trying to create a for loop to run through my program and call out a function program I have created. I have been successful in getting it to run but now I would like to simplify it one more step and shorten my program by defining y as a vector of two functions instead of y1 and y2. I tried creating a 2 cell array with the functions inside but this is a failed effort. Here is what I have.
f =cell(size(a));
f(1) =[#(t) 4*t];
f(2) =[#(t) 20+(5-t).^2];
Any advice on organizing these 2 into a vector for a single input of y?
What if you use a cell array instead:
f =cell(2,1);
f(1) ={#(t) 4*t}; %// Note the curly braces
f(2) ={#(t) 20+(5-t).^2};
OR using the following, which is more intuitive using cell arrays (thanks #rayryeng!). Assign the content of the cell with curly braces instead of doing the opposite as above.
f{1} =#(t) 4*t;
f{2} =#(t) 20+(5-t).^2;
celldisp(f)
f{1} =
#(t)4*t
f{2} =
#(t)20+(5-t).^2
Another possibility would be to define a vector-valued function whose components are your two functions:
f1 = #(t) 4*t;
f2 = #(t) 20+(5-t).^2;
f = #(t) [f1(t) f2(t)];
So for example
>> f(2.5)
>> ans =
10.0000 26.2500
I have a cell array containing functions (with function handle) and I want to evaluate these inside a for-loop. I want to evaluate the differential equations:
x1'= x2,
x2' = ax2-bx1
My code is like this:
init = [0,0];
F = {#(x1,x2) x2,#(x1,x2)(a*x2-b*x1)};
X0 = init;
for i=1:10
X = X0 + c*F(init(1),init(2));
X0 = X;
init[1] = {X(1)};
init[2] = {X(2)};
end
The constants a,b and c are given.
I get the error:
Subscript indices must either be real positive integers or logicals.
Can someone help me with this?
F is a 1x2 cell array. To access elements (in your case, function handles) within this array you must use the curly braces {} to do so. For example, the first function is retrieved by F{1} and the second by F{2} using positive integer indices.
In your example, init is a 1x2 array of zeros so when the code evaluates
F(init(1),init(2));
it is trying to access something within F using indices that are not positive. Hence the error.
I suspect that you will need to do something like the following in your for loop and evaluate each function separately
for i=1:10
for j=1:2
% get the jth function handle
func = F{j};
% evaluate
X(j) = X0(j) + c*func(init(1),init(2));
% save
end
end
I've left the save* portion to be filled in by you because it isn't all that clear to me why there are the different init,X0 and X variables - could you consolidate them?
Note also your mixture of [] and () brackets when accessing arrays. In MATLAB, if the array is of type cell, then we use the {} to access elements. For all other arrays, we use the () brackets.
First of all, there are two other problems with your code: c is not defined and you are trying to index into init with []-brackets, which will throw:
Error: File: foo Line: 8 Column: 8
Unbalanced or unexpected parenthesis or bracket.
The subscript error occurs because you are trying to access F(0,0) because init(1) and init(2) are 0. Remember that the way you declared F, it is a cell array:
>> F = {#(x1,x2) x2,#(x1,x2)(a*x2-b*x1)};
>> whos F
Name Size Bytes Class Attributes
F 1x2 288 cell
Hence, F(0,0) is illegal because indexes in matlab start with 1. Your functions reside in F{1} and F{2}.
>> F{1}
ans =
#(x1,x2)x2
>> F{2}
ans =
#(x1,x2)(a*x2-b*x1)
>> f = F{1}
f =
#(x1,x2)x2
>> f(0,0)
ans =
0
I have a defined mathematical function: f =Inline('x1^2+x2^2+2*x1*x2','x1','x2')
and I have an array that represents the number value of x1 and x2. (e.g. the array is A=[1 2])
I want to automate the process of getting the f(x1,x2), but I couldn't figure out the right way that Matlab can take in the array and assign values to x1 and x2.
What can I do to pass in the array values to the mathematical model and get the function value?
You should be using anonymous functions instead of inline since inline will be removed in a future release of MATLAB.
Example (from the docs):
sqr = #(x) x.^2;
a = sqr(5)
a =
25
In your case:
f = #(x) x(1)^2+x(2)^2+2*x(1)*x(2);
Now it expects x to be a two (or more) value array.
A = [1 2];
f(A) =
9
Note:
I don't have MATLAB on my home computer so I haven't actually tested this but it should get you going in the right direction. Have a look over the docs and you'll be fine.
The problem:
I want to index into the result of a function call that returns a variable number of output arguments without storing the result in a temporary.
getel = #(x,i) x(i); #% simple anonymous function to index into a vector
x = zeros(2,2,2);
row = getel(ind2sub(size(x), 8), 1) #% desired: 2 (row 2)
#% actual: 8 (linear index)-because ind2sub is returning 1 value only
[row col dep]=ind2sub(size(x),8) #% row=2, ind2sub returning 3 values
Example usage:
x(1).val1 = [1 2 3];
x(1).val2 = [2 1 2];
x(2).val1 = [2 1 2];
x(2).val2 = [1 0 0];
#% The normal way I would do this, with a temporary variable
[~,ind] = min(x(1).val2); #% ind=2
v(1) = x(1).val1(ind);
[~,ind] = min(x(2).val2); #% ind=2
v(2) = x(2).val1(ind);
#% I'd like to be able to do this with arrayfun:
v = arrayfun(#(s) s.val1(min(s.val2), x);
-------^ returns value of minimum, not index
The above arrayfun doesn't work - the form of min that is called returns one output: the minimum value. To make it work right, one option would be the following hypothetical function call:
v = arrayfun(#(s) s.val1(getoutputnum(2, 2, #min, s.val2)), x);
hypothetical function -----------^ ^ ^ ^-func ^--func args
which form (nargout) of func ---| |- which arg to return
I realize that for the above scenario, I could use
s.val1(find(s.val2==min(s.val2),1,'first'))
or other tricks, but that isn't possible in all cases.
In the case of ind2sub, I may want to know the index into a particular dimension (columns, say) - but the 1-output form of the function returns only a linear index value - the n-dimensional form needs to be called, even if the value of dimension 1 is what I care about.
Note: I realize that writing a function file would make this trivial: use ~ and the [out] = func(in) form. However, when writing scripts or just on the command line, it would be nice to be able to do this all within anonymous functions. I also realize that there are undoubtedly other ways to get around the problem; I would just like to know if it is possible to specify which form of a function to call, and perhaps which output number to be returned, without using the out=func(in) syntax, thus allowing functions to be nested much more nicely.
Could you do something like this?
In its own file:
function idx=mymin(x)
[~,idx] = min(x);
In your code:
v = arrayfun(#(s) s.val1(mymin(s.val2), x);
Might have syntax errors; I don't have MATLAB on the computer I'm writing this on. The idea is there though: just wrap MATLAB's min and capture the second argument, which is the logical indexing for the position of the minimum value in x.
I can get ind2sub() to return the variable number of args like this:
x = zeros(2,2,2);
c = cell(ndims(x),1);
[c{:}] = ind2sub(size(x), 8);
The c cell array will now have the 3D indices c = {2;2;2}.
[c{:}] = ind2sub(size(x), 2);
would produce c = {2;1;1}.
Is this what you were looking for?