Estoy tratando de escribir una función que tome una matriz de funciones de celda como entrada y que genere las mismas funciones, pero en un formato algo diferente.

Específicamente, quiero un vector de fila, digamos de longitud N, de funciones fVec = [f1(x, y, z), f2(x,y,z), ..., fn(x, y, z)] todas las cuales siempre generan un vector de columna de la misma longitud, digamos M. Ahora quiero que la evaluación de fVec(x, y, z) genere una matriz MXN, donde cada columna representa la salida de su vector correspondiente.

Sin embargo, debido a que Matlab no acepta matrices de manejadores de funciones regulares, debe hacerse usando matrices de celdas. (, ¿derecho?)

Además, quiero una función general que funcione para varios conjuntos de funciones, que no necesariamente tienen tres entradas. Es decir, quiero la función fVec(1, ..., x) = [f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)], lo que significa que cada una de las funciones f1, f2, fn siempre tiene el mismo número de entradas.

Por lo tanto, necesito alguna función que tome como entrada una matriz de celdas de manejadores de funciones {f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)} y genere alguna función general fVec(1, ..., x).

Ya intenté escribir una función que pensé que debería hacer esto:

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

Esto funciona para "matrices de longitud 1", obviamente. Sin embargo, existe un problema con este código. Hagamos una función de prueba, digamos testfun = @(a, b, c, d, e) a(:,3) - a(:,2) (donde testfun es una función de b, c, d, e para replicar el escenario más general), y hagamos una matriz de esta función, functionArray = {testfun, testfun}.

Ahora llamamos a nuestra función overArchingFunction = transformFunctionArray(functionArray). Sin embargo, al llamar a solution = transfun([[10 1 2]; [3 4 5]], 0, 0, 0, 0), quiero que el resultado sea:

solution =

     1     1
     1     1

Este no es el caso, porque con las declaraciones @(vars) y fun(vars), estoy restringiendo el número de variables de entrada a esta función a una sola variable, mientras que estoy tratando de pasar cinco argumentos (a saber, { {X2}}). Pensé que solucionaría este problema reemplazando vars con varargin, pero esto me da el error:

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

Resumiendo, ¿cómo conservo el número original de argumentos de entrada de f1, f2, ..., fn en overArchingFunction?

0
Sam 28 oct. 2019 a las 15:14

1 respuesta

La mejor respuesta

Lo encontré. De hecho, la respuesta está en usar varargin. Sin embargo, debido a que varargin pasa una entrada de estructura de celda, necesita acceder al contenido de esas celdas usando varargin{:}. Por tanto, la función debería ser:

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

De tal manera que los siguientes comandos den la respuesta requerida.

>> 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
0
Sam 28 oct. 2019 a las 13:24