1
votes

I was wondering how to call a function handle with an vector of inputs - rather than the list of aguments.

So if I have a function handle which is defined: (I guess it will be clear that I am working on fitting functions here)

fitFunctionHandle = @(a1, wG1, x1,a2, wG2, x2, c, x)(FitGaussianFn(x, [a1, 0, wG1, x1]) +FitGaussianFn(x, [a2, 0, wG2, x2]) + c

And I have an vector of inputs to hand to it

a1Init = 1
wG1Init = 2
x1Init = 3
a2Init = 4
wG2Init = 5
x2Init = 6
a2Init = 7
x = 8
%startPoint = [a1Init, wG1, x1,a2, wG2, x2, c]
inputArray = [a1Init, wG1, x1,a2, wG2, x2, c, x]

How do I call it with the vector startPoint as the input. If I try (for example)

>> fitFunctionHandle(inputArray)

I get an error:

Not enough input arguments.

That makes sense since it is expecting 8 inputs rather than a 8 element vector - but I'm wondering whether there is a way of calling it like that. I think for example in python you can convert an array to a list or something.

I'm aware that I could simplify things in this example case where I have a list of known inputs so I could just do:

fitFunctionHandle(a1Init, wG1, x1,a2, wG2, x2, c, x) 

or

fitFunctionHandle(inputArray(1),inputArray(2),inputArray(3,inputArray(4), inputArray(5), inputArray(6),inputArray(7),inputArray(8)) 

BUT! I guess I'm trying to allow for expansion where I don't know how many arguments there would be. For bonus points (again since I'm working on fitting functions) - It would be cool to know how to call it when x is a vector as well. I suspect that I would be doing something like

arrayfunc(fitFunctionHandle([startPoint,x]), xVector)

Thanks in advance for your help.

2

2 Answers

1
votes

Regarding the varargin, the general idea was already presented in UnbearableLightness' answer. I just wanted to address your specific case.

It seems, you want to have some dynamic linear combinations of your FitGaussianFn calls with varying parameters, resulting in some complex function handle. For variable amount of terms, I would recommend to write a separate function to generate the final function handle. I made up a small toy example.

That's my fitFunctionHandle.m function:

function h = fitFunctionHandle(varargin)

  n = numel(varargin);

  if (n < 2)
    error('Not enough input arguments.');
  end

  % Last input argument is considered t
  t = varargin{end};

  h = @(x) 0;
  for iArg = 1:n-1
    a = varargin{iArg}(1);
    b = varargin{iArg}(2);
    h = @(x) h(x) + (a*sin(b*x+t)); 
  end

end

Each input argument consists of two parameters, that form a sin term. An additional shift parameter t is always passed at last.

And, here's some test script:

% Set up parameters
a1 = 1; b1 = 1;
a2 = 2; b2 = 2;
a3 = 3; b3 = 3;
t = pi/16;

% Evaluation point
x = pi/4;

% Compare results with explicit function calls
h = fitFunctionHandle([a1, b1], t);
res = h(x)
cmp = sin(x+t)

h = fitFunctionHandle([a1, b1], [a2, b2], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t)

h = fitFunctionHandle([a1, b1], [a2, b2], [a3, b3], t);
res = h(x)
cmp = sin(x+t) + 2*sin(2*x+t) + 3*sin(3*x+t)

You see, it doesn't matter, how many parameter vectors are passed.

The output reveals, that the passed function handles are correct:

res =  0.83147
cmp =  0.83147
res =  2.7930
cmp =  2.7930
res =  4.4598
cmp =  4.4598

Regarding your last question, let's see this test:

% Set up array of t parameters, and get set of function handles
t = [pi/16, pi/8, pi/4];
hh = arrayfun(@(x) fitFunctionHandle([a1, b1], x), t, 'UniformOutput', false);

% Compare results with explicit function calls
for iH = 1:numel(hh)
  h = hh{iH};
  res = h(x)
  cmp = sin(x + t(iH))
end

Here, the t, which is used for all sin terms in fitFunctionHanle, is a vector. The arrayfun call will return a cell array of function handles. Again, the output shows comparable results:

res =  0.83147
cmp =  0.83147
res =  0.92388
cmp =  0.92388
res =  1
cmp =  1

Hope that helps!

2
votes

If I understand correctly, you are looking for a way to pass a variable number of input arguments to an anonymous function. Take a look at this example:

anonymousFunction = @(varargin)(image(varargin{:}));

x = [5 8];
y = [3 6];
C = [0 2 4 6; 8 10 12 14; 16 18 20 22];

input = {C};
anonymousFunction(input{:});

input = {x,y,C};
anonymousFunction(input{:});

You can see in the example that a variable number of inputs is used for calling the anonymous function. Of course, this depends on the actual function that is using the arguments (in this case, image)