matlabargumentsfunction-handle

How do I retain the number of arguments of a function handle when passing it to some other function in Matlab?


I am trying to write a function that takes a cell array of functions as an input and that outputs the same functions, but in a somewhat different format.

Specifically, I want a row vector, of say length N, of functions fVec = [f1(x, y, z), f2(x,y,z), ..., fn(x, y, z)] all of which always output a column vector of the same length, say M. Now I want the evaluation of fVec(x, y, z) to output an MXN matrix, where each column represents the output of its corresponding vector.

However, because Matlab doesn't accept regular function handle arrays, it must be done using cell arrays. (, right?)

Moreover, I want a general function that works for several sets of functions, that don't necessarily have three inputs. That is, I want the function fVec(1, ..., x) = [f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)], meaning that each of the funtions f1, f2, fn always have the same number of inputs.

Therefore, I need some function that takes as an input a cell array of function handles {f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)} and outputs some overarching function fVec(1, ..., x).

I already tried writing a function that I thought should do this:

function overArchingFunction = transformFunctionArray(functionArray)
    if length(functionArray) == 1
        if isa(functionArray, 'cell')
            overArchingFunction = functionArray{:};
        else
            overArchingFunction = functionArray;
        end
    else
        disp(cellfun(@(fun) fun(x), functionArray, ...
                'UniformOutput', false))
        overArchingFunction = @(vars) cell2mat(cellfun(@(fun) fun(vars), functionArray, ...
                'UniformOutput', false));
    end
end

This works for "arrays of length 1", obviously. However, there is a problem with this code. Let's make a test function, say testfun = @(a, b, c, d, e) a(:,3) - a(:,2) (where testfun is a function of b, c, d, e to replicate the most general scenario), and make an array of this function, functionArray = {testfun, testfun}.

Now we call our function overArchingFunction = transformFunctionArray(functionArray). However, when calling solution = transfun([[10 1 2]; [3 4 5]], 0, 0, 0, 0), I want the output to be:

solution =

     1     1
     1     1

This is not the case, because with the @(vars) and fun(vars) statements, I'm restricting the number of input variables to this function to only one variable, whereas I am trying to pass five arguments (namely [[10 1 2]; [3 4 5]], 0, 0, 0, 0). I though I'd fix this by replacing vars with varargin, but this gives me the error:

Attempt to execute SCRIPT varargin as a function:
/MATLAB/toolbox/matlab/lang/varargin.m

Summarising, how do I retain the original number of input arguments of f1, f2, ..., fn in the overArchingFunction?


Solution

  • I found it. The answer indeed lay in using varargin. However, because varargin passes a cell structure input, you need to access those cells' contents by using varargin{:}. The function should thus be:

    function overArchingFunction = transformFunctionArray(functionArray)
        if length(functionArray) == 1
            if isa(functionArray, 'cell')
                overArchingFunction = functionArray{:};
            else
                overArchingFunction = functionArray;
            end
        else
            overArchingFunction = @(varargin) cell2mat(cellfun(@(fun) fun(varargin{:}), 
                functionArray, ...
                    'UniformOutput', false));
        end
    end
    

    Such that the following commands give the required answer.

    >> testfun = @(a, b, c, d, e) a(:,3) - a(:,2)
    
    testfun =
    
      function_handle with value:
    
        @(a,b,c,d,e)a(:,3)-a(:,2)
    
    >> transfun = transformFunctionArray({mytestfun, mytestfun})
    
    transfun =
    
      function_handle with value:
    
        @(varargin)cell2mat(cellfun(@(fun)fun(varargin{:}),functionArray,'UniformOutput',false))
    
    >> myans = transfun([[10 1 2]; [3 4 5]], 0, 0, 0, 0)
    
    myans =
    
         1     1
         1     1