it-swarm.com.de

Wie stelle ich Standardwerte für Funktionsparameter in Matlab ein?

Ist es möglich, Standardargumente in Matlab zu haben? Zum Beispiel hier:

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

Ich möchte, dass die wahre Lösung ein optionales Argument für die Wellenfunktion ist. Kann es jemand nachweisen, wie dies möglich ist? Momentan versuche ich das, was ich oben gepostet habe und bekomme:

??? 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.
113
Scott

Es gibt keine direkte Möglichkeit, dies so zu tun, wie Sie es versucht haben.

Der übliche Ansatz besteht darin, "varargs" zu verwenden und die Anzahl der Argumente zu überprüfen. So etwas wie:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

Es gibt ein paar schickere Dinge, die Sie mit isempty usw. machen können, und Sie möchten Matlab Central nach Paketen durchsuchen, die diese Art von Dingen enthalten.

Sie können sich varargin, nargchk usw. ansehen. Sie sind nützliche Funktionen für diese Art von Dingen. Mit varargs können Sie eine variable Anzahl von abschließenden Argumenten belassen, was jedoch das Problem der Standardwerte für einige/alle nicht löst.

142
simon

Ich habe das Objekt inputParser verwendet, um die Standardeinstellungen festzulegen. Matlab akzeptiert nicht das Python-ähnliche Format, das Sie in der Frage angegeben haben, aber Sie sollten die Funktion folgendermaßen aufrufen können:

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

Nachdem Sie die wave-Funktion folgendermaßen definiert haben:

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

Nun sind die in die Funktion übergebenen Werte über i_p.Results verfügbar. Ich war mir auch nicht sicher, wie ich prüfen sollte, ob der Parameter, der für ftrue übergeben wurde, tatsächlich eine inline-Funktion war.

56
Matt

Eine andere, etwas weniger gehackte Art ist

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

Ja, es wäre wirklich schön, wenn Sie die Möglichkeit haben, das zu tun, was Sie geschrieben haben. In MATLAB ist dies jedoch nicht möglich. Viele meiner Dienstprogramme, die Standardwerte für die Argumente zulassen, werden in der Regel mit expliziten Überprüfungen am Anfang geschrieben:

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, also würde ich generell eine bessere, aussagekräftigere Fehlermeldung anwenden. Beachten Sie, dass die Überprüfung auf eine leere Variable dem Benutzer ermöglicht, ein leeres Paar [] als Platzhalter für eine Variable zu übergeben, die ihren Standardwert annimmt. Der Autor muss jedoch weiterhin den Code angeben, um dieses leere Argument durch seinen Standardwert zu ersetzen.

Meine Hilfsprogramme mit MANY-Parametern, die alle über Standardargumente verfügen, verwenden häufig eine Eigenschafts-/Wert-Paar-Schnittstelle für Standardargumente. Dieses grundlegende Paradigma zeigt sich in den Griff-Grafiktools in matlab sowie in optimset, odeset usw. 

Um mit diesen Eigenschafts-/Wert-Paaren arbeiten zu können, müssen Sie sich mit Varargin vertraut machen, um eine vollständig variable Anzahl von Argumenten in eine Funktion einzugeben. Ich habe ein Hilfsprogramm geschrieben (und gepostet), um mit solchen Eigenschafts-/Wert-Paaren zu arbeiten, parse_pv_pairs.m . Es hilft Ihnen, Eigenschafts-/Wertepaare in eine Matlab-Struktur umzuwandeln. Sie können auch Standardwerte für jeden Parameter angeben. Das Umwandeln einer schwerfälligen Liste von Parametern in eine Struktur ist eine sehr schöne Möglichkeit, sie in MATLAB herumzugeben.

10
user85109

Dies ist meine einfache Möglichkeit, mit "try" Standardwerte für eine Funktion festzulegen:

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

Grüße!

5
Jonay Cruz

Ich habe festgestellt, dass die Funktion parseArgs sehr hilfreich sein kann.

3
Mr Fooz

Es gibt auch einen "Hack", der verwendet werden kann, obwohl er zu einem bestimmten Zeitpunkt aus matlab entfernt werden kann: Function eval akzeptiert tatsächlich zwei Argumente, von denen das zweite ausgeführt wird, wenn beim ersten ein Fehler aufgetreten ist.

So können wir verwenden

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

wert 1 als Standard für das Argument verwenden

3
vuakko

Ich bin verwirrt, dass niemand darauf hingewiesen hat dieser Blog-Beitrag von Loren, einem der Matlab-Entwickler. Der Ansatz basiert auf varargin und vermeidet all diese endlosen und schmerzhaften if-then-else oder switch Fälle mit verschachtelten Bedingungen. Bei wenigen Standardwerten ist der Effekt dramatisch . Hier ist ein Beispiel aus dem verlinkten Blog:

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

Wenn Sie es immer noch nicht verstehen, lesen Sie den gesamten Blog-Beitrag von Loren. Ich habe ein Follow-up geschrieben Blogpost , das sich mit fehlenden Positions-Standardwerten befasst. Ich meine, du könntest so etwas schreiben wie:

somefun2Alt(a, b, '', 42)

und haben immer noch den Standardwert eps für den Parameter tol (und @magic Rückruf für func natürlich). Lorens Code erlaubt dies mit einer kleinen, aber kniffligen Modifikation.

Abschließend noch einige Vorteile dieses Ansatzes:

  1. Selbst bei vielen Standardeinstellungen wird der Code für das Boilerplate nicht sehr groß (im Gegensatz zur Familie von if-then-else Ansätze, die mit jedem neuen Standardwert länger werden)
  2. Alle Standardeinstellungen befinden sich an einem Ort. Wenn sich etwas ändern muss, müssen Sie sich nur einen Ort ansehen.

Trotzdem gibt es auch einen Nachteil. Wenn Sie die Funktion in Matlab Shell eingeben und ihre Parameter vergessen, wird ein nicht nützlicher varargin als Hinweis angezeigt. Um damit umzugehen, wird empfohlen, eine sinnvolle Verwendungsklausel zu schreiben.

3
alisianoi

Ich glaube, ich habe einen ziemlich raffinierten Weg gefunden, um mit diesem Problem umzugehen, da ich nur drei Codezeilen benötigte (Zeilenumbrüche sperren). Folgendes wird direkt von einer Funktion, die ich schreibe, abgehoben und scheint wie gewünscht zu funktionieren:

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

Ich dachte nur, ich würde es teilen.

3
Bonnevie

Nachdem ich ASSIGNIN (dank dieser Antwort by b3 ) und EVALIN gewusst habe, habe ich zwei Funktionen geschrieben, um endlich eine sehr einfache Aufrufstruktur zu erhalten:

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

Hier ist die Auflistung:

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

und

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
Tobias Kienzler

Dies ist mehr oder weniger aus dem Matlab Manual ; Ich habe nur vorübergehende Erfahrung ...

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
kyle

Matlab bietet hierfür keinen Mechanismus, aber Sie können einen in Userland-Code konstruieren, der eher als inputParser- oder "if nargin <1 ..." - Sequenzen ist.

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

Dann können Sie es in Ihren Funktionen so aufrufen:

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

Die Formatierung ist eine Konvention, mit der Sie von Parameternamen bis zu ihren Standardwerten herunterlesen können. Sie können Ihr getargs () mit optionalen Parametertypspezifikationen (zur Fehlererkennung oder impliziten Konvertierung) und Argumentzählbereichen erweitern.

Dieser Ansatz hat zwei Nachteile. Erstens ist es langsam, deshalb möchten Sie es nicht für Funktionen verwenden, die in Schleifen aufgerufen werden. Zweitens funktioniert die Funktionshilfe von Matlab - die Hinweise zur automatischen Vervollständigung in der Befehlszeile - nicht für Varargin-Funktionen. Aber es ist ziemlich bequem.

1
Andrew Janke

möglicherweise möchten Sie den Befehl parseparams in matlab verwenden. Die Verwendung würde wie folgt aussehen:

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
shabbychef
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;

z.B. f(2,4,'c',3) bewirkt, dass der Parameter c 3 ist.

0
Tobias Kienzler

wenn Sie Octave verwenden würden, könnten Sie dies so tun - aber leider unterstützt matlab diese Möglichkeit nicht

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

(aus dem doc genommen)

0
wuschLOR

Ich mache das gerne etwas objektorientierter. Bevor Sie wave () aufrufen, speichern Sie einige Ihrer Argumente in einem struct, z. Parameter genannt:

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

Prüfen Sie dann in der Wave-Funktion, ob die Strukturparameter ein Feld namens 'Flag' enthalten und wenn ja, ob der Wert nicht leer ist. Weisen Sie ihm dann einen zuvor definierten Standardwert oder den als Argument angegebenen Wert in den Parametern struct zu:

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

Dies erleichtert die Handhabung einer großen Anzahl von Argumenten, da sie nicht von der Reihenfolge der angegebenen Argumente abhängt. Dies ist jedoch auch hilfreich, wenn Sie später weitere Argumente hinzufügen müssen, da Sie dazu nicht die Signatur der Funktionen ändern müssen.

0
CheshireCat