Comment définir les valeurs par défaut des paramètres de fonctions dans Matlab?

est-il possible d'avoir des arguments par défaut dans Matlab? Par exemple, ici:

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

j'aimerais que la vraie solution soit un argument optionnel à la fonction wave. Si c'est possible, quelqu'un peut-il démontrer la bonne façon de le faire? Actuellement, j'essaie ce que j'ai posté ci-dessus et j'obtiens:

??? 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.
112
demandé sur nbro 2009-04-28 04:46:13

16 réponses

il n'y a pas de moyen direct de faire ça comme vous avez essayé.

l'approche habituelle est d'utiliser" varargs " et de vérifier le nombre d'arguments. Quelque chose comme:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

il y a quelques choses plus fantaisistes que vous pouvez faire avec isempty , etc., et vous pourriez vouloir regarder Matlab central pour certains paquets qui regroupent ce genre de choses.

Vous pouvez avoir un coup d'oeil à varargin , nargchk , etc. Ils sont des fonctions utiles pour ce genre de chose. varargs vous permet de laisser un nombre variable d'arguments finaux, mais cela ne vous permet pas de contourner le problème des valeurs par défaut pour certains/tous.

140
répondu simon 2018-05-29 21:41:13

j'ai utilisé l'objet inputParser pour définir les options par défaut. Matlab n'acceptera pas le format python que vous avez spécifié dans la question, mais vous devriez pouvoir appeler la fonction comme ceci:

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

après avoir défini la fonction wave comme ceci:

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{:});

maintenant les valeurs passées dans la fonction sont disponibles par i_p.Results . Aussi, je ne savais pas comment valider que le paramètre passé pour ftrue était en fait une fonction inline a donc laissé le validateur vide.

55
répondu Matt 2013-10-24 10:23:18

une autre voie un peu moins pirate est

function output = fun(input)
   if ~exist('input','var'), input='BlahBlahBlah'; end
   ...
end
18
répondu Peter 2011-02-20 15:21:27

Oui, il pourrait être vraiment sympa d'avoir la capacité de faire ce que vous avez écrit. Mais ce N'est pas possible à MATLAB. Beaucoup de mes utilitaires qui permettent les valeurs par défaut pour les arguments ont tendance à être écrits avec des vérifications explicites au début comme ceci:

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, donc je voudrais généralement appliquer un message d'erreur meilleur, plus descriptif. Voir que le contrôle pour une variable vide permet à l'utilisateur de passer dans une paire vide de crochets, [], comme un placeholder pour un variable qui prendra sa valeur par défaut. L'auteur doit toujours fournir le code pour remplacer cet argument vide avec sa valeur par défaut.

mes utilitaires qui sont plus sophistiqués, avec de nombreux paramètres, qui ont tous des arguments par défaut, utiliseront souvent une interface propriété/valeur pour les arguments par défaut. Ce paradigme de base se retrouve dans les outils graphiques de handle de matlab, ainsi que dans optimset, odeset, etc.

comme moyen de travailler avec ces paires propriété / valeur, vous aurez besoin d'en savoir plus sur varargin, comme une façon d'entrer un nombre entièrement variable d'arguments dans une fonction. J'ai écrit (et posté) un utilitaire pour travailler avec de telles paires propriété/valeur, parse_pv_pairs.m . Il vous aide à convertir des paires de propriétés/valeurs en une structure matlab. Il vous permet également de fournir des valeurs par défaut pour chaque paramètre. Convertir une liste complexe de paramètres en une structure est une très bonne façon de les passer dans MATLAB.

10
répondu 2009-04-28 11:56:57

c'est ma façon simple de définir les valeurs par défaut d'une fonction, en utilisant "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

salutations!

5
répondu Jonay Cruz 2015-06-09 14:01:02

j'ai trouvé que la fonction parseArgs peut être très utile.

3
répondu Mr Fooz 2009-04-28 21:00:52

il y a aussi un "hack" qui peut être utilisé bien qu'il puisse être retiré de matlab à un moment donné: La fonction eval accepte en fait deux arguments dont le second est lancé si une erreur s'est produite avec le premier.

donc nous pouvons utiliser

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

pour utiliser la valeur 1 par défaut pour l'argument

3
répondu vuakko 2010-12-07 09:30:38

je crois que j'ai trouvé un moyen tout à fait astucieux de traiter cette question, en ne prenant que trois lignes de code (sauf ligne wraps). Ce qui suit est tiré directement d'une fonction que j'écris, et il semble fonctionner comme désiré:

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

j'ai pensé le partager.

3
répondu Bonnevie 2014-01-16 14:18:21

je suis confus personne n'a signalé ce billet de blog par Loren, un des développeurs de Matlab. L'approche est basée sur varargin et évite tous ces interminables et douloureux if-then-else ou switch cas avec des conditions alambiquées. Quand il y a quelques valeurs par défaut, l'effet est dramatique . Voici un exemple tiré du blog en lien:

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 vous ne le faites toujours pas obtenez-le, puis essayez de lire l'ensemble de l'article de blog par Loren. J'ai écrit un suivi post de blog qui traite de manquant valeurs par défaut de position. Je veux dire que vous pourriez écrire quelque chose comme:

somefun2Alt(a, b, '', 42)

et ont toujours la valeur par défaut eps pour le paramètre tol (et @magic pour func bien sûr). Le code de Loren permet cela avec une légère mais délicate modification.

enfin, quelques avantages de cette approche:

  1. même avec un grand nombre de valeurs par défaut, le code du boilerplate ne devient pas énorme (par opposition à la famille des approches if-then-else , qui s'allongent avec chaque nouvelle valeur par défaut)
  2. Toutes les valeurs par défaut sont en un seul endroit. Si l'un de ces besoin de changer, vous avez un seul endroit à regarder.

Trooth être dit, il y a un désavantage. Lorsque vous tapez la fonction dans le shell Matlab et oubliez ses paramètres, vous verrez un varargin inutile comme un indice. Pour faire face à cela, vous êtes conseillé d'écrire une clause d'utilisation significative.

3
répondu alisianoi 2014-06-17 16:58:18

après avoir pris conscience de ASSIGNIN (merci à cette réponse par b3 ) et EVALIN j'ai écrit deux fonctions pour obtenir finalement une structure d'appel très simple:

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

Voici la liste:

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

et

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 ')']) ;
2
répondu Tobias Kienzler 2017-05-23 12:10:33

Ceci est plus ou moins levé du Matlab manuel ; Je n'ai qu'une expérience de passage...

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
1
répondu kyle 2009-04-28 02:36:17

Matlab ne fournit pas de mécanisme pour cela, mais vous pouvez construire un en code userland qui est plus terser que inputParser ou "si nargin < 1..." séquence.

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

, Alors vous pouvez l'appeler dans vos fonctions comme ceci:

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

le formatage est une convention qui vous permet de lire vers le bas des noms de paramètres à leurs valeurs par défaut. Vous pouvez étendre votre getargs () avec les spécifications de type de paramètre optionnel (pour la détection d'erreur ou conversion implicite) et les intervalles de comptage des arguments.

cette approche comporte deux inconvénients. Tout d'abord, il est lent, donc vous ne voulez pas l'utiliser pour les fonctions qui sont appelées en boucles. Deuxièmement, L'aide de fonction de Matlab - les conseils d'autocompletion sur la ligne de commande - ne fonctionne pas pour les fonctions varargin. Mais il est très pratique.

1
répondu Andrew Janke 2009-05-13 04:18:36

vous pourriez vouloir utiliser la commande parseparams dans matlab; l'utilisation ressemblerait à:

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;
0
répondu shabbychef 2010-10-08 19:04:52
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;

par exemple f(2,4,'c',3) fait que le paramètre c est 3.

0
répondu Tobias Kienzler 2010-10-11 13:56:52

si vous utilisiez octave vous pourriez le faire comme ceci - mais malheureusement matlab ne supporte pas cette possibilité

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

(tiré du doc )

0
répondu wuschLOR 2014-06-10 14:09:18

j'aime le faire d'une manière un peu plus orientée objet. Avant d'appeler wave() sauvegardez certains de vos arguments dans une struct, par exemple. un appelé paramètres:

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

dans la fonction wave puis vérifier, si les paramètres struct contiennent un champ appelé 'flag' et si oui, si sa valeur est non vide. Puis l'affecter dans une valeur par défaut que vous définissez avant, ou la valeur donnée comme argument dans les paramètres 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

Cela rend plus facile de manipuler un grand nombre d'arguments, car il ne dépend pas de l'ordre des arguments donnés. Cela dit, il est également utile si vous devez ajouter plus d'arguments plus tard, parce que vous n'avez pas à changer la signature des fonctions pour le faire.

0
répondu CheshireCat 2018-05-24 12:04:16