Passing A Variable Number of Arguments into a Function - matlab

In Matlab, I have a variable length cell of values:
C={A1,...,An}
How should I pass and distribute these values into a function able to receive a variable number of arguments?
f(A1,...,An)
Ultimately if not possible, how should I modify the beginning of this function for making this work?

You need to convert the cell array into a comma-separated list via curly-brace indexing, that is, use C{:}.
Example with the reshape function:
>> C = {ones(3,4), 2, 2, 3};
>> y = reshape(C{:});
>> size(y) % check
ans =
2 2 3

This is exactly what 'varargin' does for you. Read in multiple variables, e.g. f(a,b,c), and store them in a cell-array.
Then you could go for one of these 'quick and dirty' processing methods:
function asdf(varargin)
yourarguments=[varargin{:}]; % if all numerical
yourargumentscontain=contains(varargin,'asdf'); %if strings contained
all_processed_args=cellfun(#(x) whateveryouwant_function(x), varargin); %for older versions of matlab
end
For more here's documentation: https://ch.mathworks.com/help/matlab/matlab_prog/parse-function-inputs.html

Related

MATLAB: return both arguments from ISMEMBER when used inside SPLITAPPLY

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);

Evaluate multiple values in a function matlab

I have defined a function in matlab:
function1 = #(x,y,z)[x*y*z,y^2,x+z]
Then in the program I want to writ, I want to evaluate the values of this function for (1,2,3).
Outside the program I can use feval(function1,1,2,3) and this returns
6 4 4.
Now inside my program, I want the input to be like this: output = program(fun, vec), where vec is a vector like [1,2,3].
If I now call: feval(fun,vec) I get the following error message:
Error using #(x,y,z)[x*y*z,y^2,x+z]
Not enough input arguments.
Can someone tell me how I can evaluate the values of my function when the input is a vector instead of three seperate numbers?
Many thanks!
You need a comma-separated list. Define your vector vec as follows:
vec = {1 2 3}
or use
vec = [1 2 3]
vec = num2cell{vec}
and then call feval:
feval(fun,vec{:})
It is actually obsolete to evaluate functions with feval, the following is equivalent:
function1(1,2,3)
function1(vec{:})
As you want to pass the vector vec to your program you need to modify your program to either accepted a various number of inputs with varargin:
program(fun, vec{:))
or you change the evaluation of vec inside your function to vec{:}
You are creating anonymous functions, and they can be used with the following syntax:
myfun= #(x,y,z)([x*y*z,y^2,x+z])
res=myfun(1,2,3);
vect=[1 2 3]
res2=myfun(vect(1),vect(2),vect(3));
In general I would try to avoid using feval.

How to split an array as argument values in matlab?

In my matlab script, I have a function handler
F=#(x1,x2)6+2*x1^1+3*x2^2;
This gives me an anonymous function as F that takes 2 arguments and returns the value. I also have an array of values
x = [1 2];
With the above, how can I do
F(x)
In other words, something like F(1, 2) but I want to use x, I don't want to hard code values, and it also needs to work for any dimension size, I don't want to hard code it for 2-dimension like in the above example. Basically what I'm looking for is a way to turn an array into arguments.
Can this be done in matlab?
Thanks
To turn an array into its arguments: first turn the array into a cell array (with num2cell), and then turn the cell array into a comma-separated list (with {:}):
xcell = num2cell(x);
F(xcell{:})
Does this work?
F=#(x)6+2*x(1)^1+3*x(2)^2;
xx = [1 2];
F(xx)
ans =
20

Matlab Function with Varying parameters

I need help figuring out how to code the following problem. Any help would be greatly appreciated!
Create a function that will take a vector/array input for x (1 by n) and a scalar input for a, and produce the output defined by the following equation:
y(x,a)=((xsin(ax-2))/(sqrt(1+(ax)^2)
-π ≤ x ≤ π
a={.5 1 1.5 2}
The equation must be vectorized in terms of x and the output from the function is the array y which has the same dimension as the array x.
Write a script that calls this function to compute y(x,a) for the range of x defined above and each value of the parameter a. Results should be stored in a solution matrix using a different row of the solution matrix for each value of a.
So far for my function I have:
function [y] = part1(a,x)
y=((x*sin(a*x-2))/(sqrt(1+(a*x).^2)));
end
I'm not sure how to output this into the solution matrix
For my script I have:
%%
clear,clc
a={0.5 1 1.5 2};
x=-pi:0.1:pi;
for
part1(x,a)
end
I'm getting the following errors when I run this now:
Undefined function 'mtimes' for input arguments of type 'cell'.
Error in part1 (line 4)
y=((x*sin(a*x-2))/(sqrt(1+(a*x).^2)));
Error in labtest2 (line 8)
y(i,:)=part1(x,a(i));
EDIT
I've made some changes and am still getting some errors that I cannot resolve.
Here is my full code for function followed by full code for script:
Function
function [y] = part1(x,a)
nx=numel(x);
na=numel(a);
y=((x.*sin(a.*x-2))./(sqrt(1+(a.*x).^2)));
size(y)=[nx na]
end
Script
%%
clear,clc
a={0.5 1 1.5 2};
x=-pi:0.1:pi;
for i = 1:length(a)
y(i,:)=part1(x,a(i));
end
Errors
Undefined function 'times' for input arguments of type 'cell'.
Error in part1 (line 6)
y=((x.*sin(a.*x-2))./(sqrt(1+(a.*x).^2)));
Error in labtest2 (line 8)
y(i,:)=part1(x,a(i));
The reason you're getting Undefined function 'times' for input arguments of type 'cell' is because your variable a is a cell array. You need to change your assignment of a from
a={0.5 1 1.5 2};
to
a=[0.5 1 1.5 2];
which will make it just a normal array. Alternatively, you need to reference it with cell array notation: a{i} instead of a(i).
You're almost there. Note that you've written
function [y] = part1(a,x)
but you call it in your script as
part1(x,a)
so you should probably correct that.
A few things jump out at me:
You never assign the output of part1(x,a) to anything. You're told that
Results should be stored in a solution matrix using a different row of the solution matrix for each value of a.
What I take this to mean is that the 1st row corresponds to part1() evaluated for the 1st element of a. Since we're operating on x which is a vector, that row will have multiple columns. Your output is indeed a matrix. In your case, length(-pi:0.1:pi) == 63, therefore size(y) == [4 63], where y is your output matrix.
Your for loop is backwards. You're told to accept scalar a and vector x. Therefore, your script should be something like:
a = 0.5:0.5:2;
x = -pi:0.1:pi;
for i = 1:length(a)
y(i,:) = part1(x, a(i));
end
Note the use of length and the : operator. I want to iterate between 1 to length(a) (in this case, length(a) == 4) so that I can use the current a(i) value as an index into my output matrix, y. The : operator in y(i,:) signifies "The ith row and all columns of y will take the value output by part1(x,a(i))."
Your function needs to be changed up for element-by-element operations. Notice that, for instance, x*sin(a*x-2) works for scalar x but not vectors. This is because x is a vector and sin(a*x-2) is also a vector (since the sin call will operate element-by-element and a is a scalar). Trying to multiply two vectors together will result in errors since MATLAB will try to perform a matrix multiplication. Resolve this by replacing * with .*. This way it is unambiguous that you are going to multiply these two vectors element-by-element. You'll also need to change / to ./.
On another note, thank you for attempting to do your homework before asking SO for help. We've been getting a huge influx of questions from students that have made no attempt to do their own work before dumping it on us, so it's refreshing that we regulars of the MATLAB tag get to actual help out instead of telling people to do their own work.
Finally got the whole thing worked out.
Function
function [y] = part1(x,a)
y=((x.*sin(a.*x - 2))./(sqrt(1 + (a.*x).^2)));
end
Script
%%
clear all;
clc;
close all;
x=[-pi:.1:pi];
a=[.5:.5:2];
for i=1:length(a)
y(i,:)=part1(x,a(i));
plot(x,y)
end
Sol=[y]

Find index of all (non-unique) elements in a cell array as they appear in a second (sorted and unique) cell array

A = {'A'; 'E'; 'A'; 'F'};
B = {'A';'B';'C';'D';'E'; 'F'};
I am trying to get for each string in cell array A, the index that matches that string in cell array B. A will have repeated values, B will not.
find(ismember(B, A) == 1)
outputs
1
5
6
but I want to get
1
5
1
6
preferably in a one liner. I can't use strcmp instead of ismember either as the vectors are different sizes.
The vectors will actually contain date strings, and I need the index not a logical index matrix, I'm interested in the number not to use it for indexing.
How do I do it?
You flip the arguments to ismember, and you use the second output argument:
[~,loc]=ismember(A,B)
loc =
1
5
1
6
The second output tells you where the elements of A are in B.
If you are working with very strict limits to how many lines you can have in your code, and are in no position to fire the manager who imposed such limitations, you may want to access the second output of ismember directly. In order to do this, you can create the following helper function that allows to directly access the i-th output of a function
function out = accessIthOutput(fun,ii)
%ACCESSITHOUTPUT returns the i-th output variable of the function call fun
%
% define fun as anonymous function with no input, e.g.
% #()ismember(A,B)
% where A and B are defined in your workspace
%
% Using the above example, you'd access the second output argument
% of ismember by calling
% loc = accessIthOutput(#()ismember(A,B),2)
%# get the output
[output{1:ii}] = fun();
%# return the i-th element
out = output{ii};