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
Related
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{:})
I have a cell C in Matlab of dimension mx1, e.g. m=3
C={{1 2 3} {4 5 6} {7 8 9 10}}
Then I have a function g written in a separate m-file
function D=g(C{i},a,b)
...
end
that takes any sub-cell C{i} of C and using some other parameters a and b gives a vector D of dimension fx1.
I want to apply the function g to each sub-cell of C and assemble the obtained fx1 vectors in a matrix fxm without using loops. I have seen the command cellfun but I don't know how to make it working with a function written by myself. Any suggestion?
Simple. First make a handle to the function where the only input is the cell array:
h = #(x) D(x, a, b);
Here, x would be a cell from the cell array. Also, I'm going to assume that a and b are already defined in your workspace. After, just do this:
out = cellfun(h, C, 'uni', 0);
The first argument is a handle to the function, which we've already defined. The next parameter is the cell array you want to operate on and apply the function h to every cell in your array. You need to specify the uni=0 flag because the output is non-uniform. Because your function outputs a vector per cell, this is mandatory. If your function outputted a single value, then this declaration of uni=0 is not required.
Alternatively, you can do this in a loop... which is what cellfun ultimately performs:
out = cell(numel(C), 1);
for idx = 1 : numel(C)
out{idx} = D(C{idx}, a, b);
end
To me, the second option is more suitable for those who aren't used to using cellfun.
I am trying out one of the matlab programming question.
Question:
Write a function called hulk that takes a row vector v as an input and
returns a matrix H whose first column consist of the elements of v,
whose second column consists of the squares of the elements of v, and
whose third column consists of the cubes of the elements v. For
example, if you call the function likes this, A = hulk(1:3) , then A
will be [ 1 1 1; 2 4 8; 3 9 27 ].
My Code:
function H = hulk(v)
H = [v; v.^2; v.^3];
size(H) = (n,3);
end
When I test my code using A = hulk(1:3), it throws an error on console.
Your function made an error for argument(s) 0
Am I doing something incorrect? Have I missed anything?
Remove the line size(H) = (n,3);
and add the line H = H';
Final code should be as follows
function H = hulk(v)
H = [v; v.^2; v.^3];
H = H';
end
Your code giving error in matlab editor on the size(H) = (n,3); line
That's why you should use the matlabeditor itself
For your future reference, you can very easily generalise this function in Matlab to allow the user to specify the number of cols in your output matrix. I also recommend that you make this function a bit more defensive by ensuring that you are working with column vectors even if your user submits a row vector.
function H = hulk(v, n)
%//Set default value for n to be 3 so it performs like your current function does when called with the same signature (i.e. only 1 argument)
if nargin < 2 %// nargin stands for "Number of ARGuments IN"
n = 3;
end if
%// Next force v to be a row vector using this trick (:)
%// Lastly use the very useful bsxfun function to perform the power calcs
H = bsxfun(#power, v(:), 1:n);
end
You could reduce the number of operations using cumprod. That way, each v.^k is computed as the previous v.^k times v:
function H = hulk(v, n)
H = cumprod(repmat(v,n,1),1);
The first input argument is the vector, and the second is the maximum exponent.
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
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?