¿Cómo configuro los valores predeterminados para los parámetros de funciones en Matlab?

¿Es posible tener argumentos predeterminados en Matlab? Por ejemplo, aquí:

function wave(a, b, n, k, T, f, flag, fTrue=inline('0')) 

Me gustaría que la verdadera solución sea un argumento opcional para la función de onda. Si es posible, ¿alguien puede demostrar la forma correcta de hacerlo? Actualmente, estoy intentando lo que publiqué anteriormente y obtengo:

 ??? Error: File: wave.m Line: 1 Column: 37 The expression to the left of the equals sign is not a valid target for an assignment. 

No hay una manera directa de hacer esto como lo has intentado.

El enfoque habitual es usar “varargs” y comparar con el número de argumentos. Algo como:

 function f(arg1, arg2, arg3) if nargin < 3 arg3 = 'some default' end end 

Hay algunas cosas más divertidas que puede hacer con isempty , etc., y es posible que desee consultar el centro de Matlab para algunos paquetes que combinan este tipo de cosas.

Puede echar un vistazo a varargin , nargchk , etc. Son funciones útiles para este tipo de cosas. Los varargs le permiten dejar una cantidad variable de argumentos finales, pero esto no le ayuda a resolver el problema de los valores predeterminados para algunos / todos ellos.

He usado el objeto inputParser para tratar de establecer las opciones predeterminadas. Matlab no aceptará el formato tipo python que especificó en la pregunta, pero debería poder llamar a la función de esta manera:

 wave(a,b,n,k,T,f,flag,'fTrue',inline('0')) 

Después de definir la función de wave esta manera:

 function wave(a,b,n,k,T,f,flag,varargin) i_p = inputParser; i_p.FunctionName = 'WAVE'; i_p.addRequired('a',@isnumeric); i_p.addRequired('b',@isnumeric); i_p.addRequired('n',@isnumeric); i_p.addRequired('k',@isnumeric); i_p.addRequired('T',@isnumeric); i_p.addRequired('f',@isnumeric); i_p.addRequired('flag',@isnumeric); i_p.addOptional('ftrue',inline('0'),1); i_p.parse(a,b,n,k,T,f,flag,varargin{:}); 

Ahora los valores pasados ​​a la función están disponibles a través de i_p.Results . Además, no estaba seguro de cómo validar que el parámetro pasado por ftrue era en realidad una función en inline , por lo que dejó el validador en blanco.

Otra forma un poco menos hacky es

 function output = fun(input) if ~exist('input','var'), input='BlahBlahBlah'; end ... end 

Sí, podría ser realmente bueno tener la capacidad de hacer lo que usted ha escrito. Pero no es posible en MATLAB. Muchas de mis utilidades que permiten los valores predeterminados de los argumentos tienden a escribirse con comprobaciones explícitas al principio como esta:

 if (nargin<3) or isempty(myParameterName) MyParameterName = defaultValue; elseif (.... tests for non-validity of the value actually provided ...) error('The sky is falling!') end 

Ok, entonces generalmente aplicaría un mensaje de error mejor y más descriptivo. Observe que la comprobación de una variable vacía le permite al usuario pasar un par de corchetes vacíos, [], como marcador de posición para una variable que tomará su valor predeterminado. Sin embargo, el autor debe suministrar el código para reemplazar ese argumento vacío con su valor predeterminado.

Mis utilidades que son más sofisticadas, con MUCHOS parámetros, todos los cuales tienen argumentos predeterminados, a menudo usarán una interfaz de paridad propiedad / valor para los argumentos predeterminados. Este paradigma básico se ve en las herramientas de manejo de gráficos en matlab, así como en optimset, odeset, etc.

Como un medio para trabajar con estos pares de propiedad / valor, tendrá que aprender sobre varargin, como una forma de ingresar una cantidad totalmente variable de argumentos a una función. Escribí (y publiqué) una utilidad para trabajar con dichos pares de propiedad / valor, parse_pv_pairs.m . Le ayuda a convertir pares de propiedad / valor en una estructura de matlab. También le permite suministrar valores predeterminados para cada parámetro. Convertir una lista inmanejable de parámetros en una estructura es una manera MUY agradable de pasarlos en MATLAB.

Esta es mi manera simple de establecer valores predeterminados para una función, usando “try”:

 function z = myfun (a,varargin) %% Default values b = 1; c = 1; d = 1; e = 1; try b = varargin{1}; c = varargin{2}; d = varargin{3}; e = varargin{4}; end %% Calculation z = a * b * c * d * e ; end 

¡Saludos!

Descubrí que la función parseArgs puede ser muy útil.

También hay un ‘hack’ que puede usarse aunque se elimine de matlab en algún momento: Function eval acepta realmente dos argumentos, de los cuales el segundo se ejecuta si ocurre un error con el primero.

Por lo tanto, podemos usar

 function output = fun(input) eval('input;', 'input = 1;'); ... end 

para usar el valor 1 como predeterminado para el argumento

Creo que encontré una forma bastante ingeniosa de manejar este problema, ocupando solo tres líneas de código (excepto las líneas bloqueadas). Lo siguiente se elimina directamente de una función que estoy escribiendo, y parece funcionar como se desea:

 defaults = {50/6,3,true,false,[375,20,50,0]}; %set all defaults defaults(1:nargin-numberForcedParameters) = varargin; %overload with function input [sigma,shifts,applyDifference,loop,weights] = ... defaults{:}; %unfold the cell struct 

Solo pensé en compartirlo.

Estoy confundido, nadie ha señalado esta publicación del blog de Loren, uno de los desarrolladores de Matlab. El enfoque se basa en varargin y evita todos esos interminables y dolorosos if-then-else o switch caso con condiciones intrincadas. Cuando hay unos pocos valores predeterminados, el efecto es dramático . Aquí hay un ejemplo del blog vinculado:

 function y = somefun2Alt(a,b,varargin) % Some function that requires 2 inputs and has some optional inputs. % only want 3 optional inputs at most numvarargs = length(varargin); if numvarargs > 3 error('myfuns:somefun2Alt:TooManyInputs', ... 'requires at most 3 optional inputs'); end % set defaults for optional inputs optargs = {eps 17 @magic}; % now put these defaults into the valuesToUse cell array, % and overwrite the ones specified in varargin. optargs(1:numvarargs) = varargin; % or ... % [optargs{1:numvarargs}] = varargin{:}; % Place optional args in memorable variable names [tol, mynum, func] = optargs{:}; 

Si aún no lo obtiene, intente leer la publicación completa del blog de Loren. He escrito una publicación de seguimiento del blog que trata sobre los valores predeterminados de posición faltantes . Quiero decir que podrías escribir algo como:

 somefun2Alt(a, b, '', 42) 

y todavía tienen el valor de eps predeterminado para el parámetro de tol (y la callback de @magic por supuesto, por supuesto). El código de Loren permite esto con una ligera pero complicada modificación.

Finalmente, solo unas pocas ventajas de este enfoque:

  1. Incluso con muchos incumplimientos, el código repetitivo no se vuelve enorme (a diferencia de la familia de enfoques if-then-else , que se hacen más largos con cada nuevo valor predeterminado)
  2. Todos los valores predeterminados están en un solo lugar. Si alguno de ellos necesita cambiar, solo tiene un lugar para mirar.

Trooth sea dicho, también hay una desventaja. Cuando escribe la función en el shell de Matlab y olvida sus parámetros, verá un varargin inútil como una pista. Para lidiar con eso, se recomienda escribir una cláusula de uso significativo.

Después de tomar consciencia de ASSIGNIN (gracias a esta respuesta por b3 ) y EVALIN escribí dos funciones para finalmente obtener una estructura de llamadas muy simple:

 setParameterDefault('fTrue', inline('0')); 

Aquí está la lista:

 function setParameterDefault(pname, defval) % setParameterDefault(pname, defval) % Author: Tobias Kienzler (https://stackoverflow.com/users/321973) % sets the parameter NAMED pname to the value defval if it is undefined or % empty if ~isParameterDefined('pname') error('paramDef:noPname', 'No parameter name defined!'); elseif ~isvarname(pname) error('paramDef:pnameNotChar', 'pname is not a valid varname!'); elseif ~isParameterDefined('defval') error('paramDef:noDefval', ['No default value for ' pname ' defined!']); end; % isParameterNotDefined copy&pasted since evalin can't handle caller's % caller... if ~evalin('caller', ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) callername = evalin('caller', 'mfilename'); warnMsg = ['Setting ' pname ' to default value']; if isscalar(defval) || ischar(defval) || isvector(defval) warnMsg = [warnMsg ' (' num2str(defval) ')']; end; warnMsg = [warnMsg '!']; warning([callername ':paramDef:assigning'], warnMsg); assignin('caller', pname, defval); end 

y

 function b = isParameterDefined(pname) % b = isParameterDefined(pname) % Author: Tobias Kienzler (https://stackoverflow.com/users/321973) % returns true if a parameter NAMED pname exists in the caller's workspace % and if it is not empty b = evalin('caller', ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) ; 

Esto está más o menos levantado del manual de Matlab ; Solo tengo experiencia pasajera …

 function my_output = wave ( a, b, n, k, T, f, flag, varargin ) optargin = numel(varargin); fTrue = inline('0'); if optargin > 0 fTrue = varargin{1}; end % code ... end 

Matlab no proporciona un mecanismo para esto, pero puede construir uno en el código de usuario que sea más terser que inputParser o secuencias “if nargin <1 ...".

 function varargout = getargs(args, defaults) %GETARGS Parse function arguments, with defaults % % args is varargin from the caller. By convention, a [] means "use default". % defaults (optional) is a cell vector of corresponding default values if nargin < 2; defaults = {}; end varargout = cell(1, nargout); for i = 1:nargout if numel(args) >= i && ~isequal(args{i}, []) varargout{i} = args{i}; elseif numel(defaults) >= i varargout{i} = defaults{i}; end end 

Entonces puede llamarlo en sus funciones de esta manera:

 function y = foo(varargin) %FOO % % y = foo(a, b, c, d, e, f, g) [a, b, c, d, e, f, g] = getargs(varargin,... {1, 14, 'dfltc'}); 

El formato es una convención que le permite leer desde los nombres de los parámetros a sus valores predeterminados. Puede ampliar sus getargs () con especificaciones de tipo de parámetro opcionales (para detección de errores o conversión implícita) y rangos de recuento de argumentos.

Hay dos inconvenientes en este enfoque. En primer lugar, es lento, por lo que no desea utilizarlo para las funciones que se llaman en bucles. En segundo lugar, la función de ayuda de Matlab – las sugerencias de autocompletado en la línea de comando – no funcionan para las funciones varargin. Pero es bastante conveniente.

es posible que desee utilizar el comando parseparams en matlab; el uso se vería así:

 function output = wave(varargin); % comments, etc [reg, props] = parseparams(varargin); ctrls = cell2struct(props(2:2:end),props(1:2:end),2); %yes this is ugly! a = reg{1}; b = reg{2}; %etc fTrue = ctrl.fTrue; 
 function f(arg1, arg2, varargin) arg3 = default3; arg4 = default4; % etc. for ii = 1:length(varargin)/2 if ~exist(varargin{2*ii-1}) error(['unknown parameter: ' varargin{2*ii-1}]); end; eval([varargin{2*ii-1} '=' varargin{2*ii}]); end; 

eg f(2,4,'c',3) hace que el parámetro c sea ​​3.

si usas la octava, puedes hacerlo así, pero lamentablemente el matlab no admite esta posibilidad

 function hello (who = "World") printf ("Hello, %s!\n", who); endfunction 

(tomado del documento )

Me gusta hacer esto de una manera algo más orientada a objetos. Antes de llamar a wave () guarda algunos de tus argumentos dentro de una estructura, ej. uno llamado parámetros:

 parameters.flag =42; parameters.fTrue =1; wave(a,b,n,k,T,f,parameters); 

Dentro de la función de onda, luego verifique si los parámetros de estructura contienen un campo llamado ‘bandera’ y, de ser así, si su valor no está vacío. Luego, asígnele un valor predeterminado que defina antes, o el valor dado como argumento en los parámetros struct:

 function output = wave(a,b,n,k,T,f,parameters) flagDefault=18; fTrueDefault=0; if (isfield(parameters,'flag') == 0 || isempty(parameters.flag)),flag=flagDefault;else flag=parameters.flag; end if (isfield(parameter,'fTrue') == 0 || isempty(parameters.fTrue)),fTrue=fTrueDefault;else fTrue=parameters.fTrue; end ... end 

Esto facilita el manejo de un gran número de argumentos, ya que no depende del orden de los argumentos dados. Dicho esto, también es útil si debe agregar más argumentos más adelante, porque no tiene que cambiar la firma de las funciones para hacerlo.