Matlabで関数パラメーターのデフォルト値を設定するにはどうすればよいですか?


126

Matlabでデフォルトの引数を持つことは可能ですか?たとえば、ここ:

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

私は本当の解決策を波動関数のオプションの引数にしたいと思います。可能であれば、誰でもこれを行う適切な方法を示すことができますか?現在、私は私が上に投稿したものを試していると私は得ます:

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

回答:


151

あなたが試みたようにこれを行う直接的な方法はありません。

通常のアプローチは、 "varargs"を使用して、引数の数をチェックすることです。何かのようなもの:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

isemptyなどを使用して実行できるより洗練された機能がいくつかあります。これらの種類のものをバンドルするいくつかのパッケージについては、Matlabセントラルを参照することをお勧めします。

あなたは見ているかもしれないvararginnargchk彼らはこの種のもののために便利な機能だなど、。varargsを使用すると、可変数の最終引数を残すことができますが、一部またはすべてのデフォルト値の問題を回避することはできません。


58

inputParserオブジェクトを使用して、デフォルトオプションの設定を処理しました。Matlabは質問で指定したpythonのような形式を受け入れませんが、次のような関数を呼び出すことができるはずです。

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

waveこのように関数を定義した後:

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

これで、関数に渡された値はを介して利用できますi_p.Results。また、渡されたパラメーターftrueが実際にinline関数であることを検証する方法がわからなかったため、バリデーターを空白のままにしました。


7
私が知ることができるように、これは推奨される方法です。それは、クリーンで自己文書化されており(より多くのif nargin文言を含む)、保守が容易で、コンパクトで、柔軟性があります。
JnBrymn 2011年

19

もう少しハックの少ない方法は

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

Coderは "exist"関数をサポートしていないため、MATLAB Coderを使用してCコードを生成する場合、このオプションは機能しません。
Dave Tillman、2018年

10

はい、あなたが書いたように実行する機能を持っていることは本当に素晴らしいかもしれません。しかし、MATLABでは不可能です。引数のデフォルトを許可する私のユーティリティの多くは、最初は次のように明示的なチェックで記述される傾向があります。

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

わかりました、それで私は一般により良い、より説明的なエラーメッセージを適用します。空の変数のチェックにより、ユーザーは、デフォルト値をとる変数のプレースホルダーとして、空の大括弧[]のペアを渡すことができます。ただし、作成者は、空の引数をデフォルト値に置き換えるコードを提供する必要があります。

多くのパラメーターがあり、すべてデフォルトの引数を持つ、より洗練された私のユーティリティは、多くの場合、デフォルトの引数にプロパティ/値ペアインターフェイスを使用します。この基本的なパラダイムは、MATLABのハンドルグラフィックスツールや、optimset、odesetなどで見られます。

これらのプロパティと値のペアを操作する手段として、関数に完全に可変数の引数を入力する方法として、vararginについて学ぶ必要があります。このようなプロパティと値のペアparse_pv_pairs.mを操作するユーティリティを作成(および投稿)しました。プロパティと値のペアをMATLAB構造に変換するのに役立ちます。また、各パラメーターのデフォルト値を指定することもできます。扱いにくいパラメーターのリストを構造体に変換することは、MATLABでパラメーターを渡すのにとても良い方法です。


6

これは、 "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

よろしく!



3

ある時点でmatlabから削除される可能性がありますが、使用できる「ハック」もあります。関数evalは実際に2番目の引数を受け入れ、最初の引数でエラーが発生した場合に2番目の引数が実行されます。

したがって、使用できます

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

引数のデフォルトとして値1を使用するには


3

私はこの問題に対処するためのかなり気の利いた方法を見つけたと信じています。以下は私が書いている関数から直接持ち上げられており、それは望み通りに機能するようです:

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

共有しようと思ったところです。


3

Matlabの開発者の1人であるLorenによるこのブログ投稿を誰も指摘しなかったことに混乱しています。このアプローチはvarargin、これらの無限で痛みを伴う、if-then-elseまたはswitch複雑な状態のケースに基づいており、それらを回避します。ある場合、いくつかのデフォルト値は、効果がある劇的な。リンクされたブログの例を以下に示します。

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

それでもうまくいかない場合は、ローレンのブログ投稿全体を読んでみてください。位置のデフォルト値が不足していることを扱ったフォローアップブログ投稿を書きました。私はあなたが次のようなものを書くことができることを意味します:

somefun2Alt(a, b, '', 42)

パラメータのデフォルトepstol(そしてもちろん@magicコールバックfunc)がまだあります。ローレンのコードはこれをわずかにトリッキーな修正で可能にします。

最後に、このアプローチのいくつかの利点:

  1. 多くのデフォルトがある場合でも、ボイラープレートコードは大きくなりません(if-then-else新しいデフォルト値ごとに長くなる一連のアプローチとは対照的)。
  2. すべてのデフォルトは1か所にあります。それらのいずれかを変更する必要がある場合は、1か所しか確認できません。

トロスは言われる、不利な点もあります。Matlabシェルで関数を入力してそのパラメーターを忘れるvararginと、ヒントとして役に立たないことがわかります。これに対処するには、意味のある使用法を記述することをお勧めします。


フォローアップのブログ投稿へのリンクが壊れています。直せますか
equaeghe

2

意識になってきた後assigninを(のおかげで、この答えによるB3)と関数evalin私は最終的に非常に単純な呼び出し元の構造を得るために2つの関数を書きました:

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

これがリストです:

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

そして

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

1

これは、多かれ少なかれ、Matlabのマニュアルから外されています。私は経験を積んだだけです...

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
私が修正したコードにはいくつかのエラーがありました。まず、「optargin」を定義する必要があります。2番目に、「varargin」は後続のすべての入力を収集するセル配列であるため、セル配列のインデックスを使用して値を削除する必要があります。
gnovice

ビジョンを確認する必要があります。昨日はマニュアルでそれを見たことがないと誓います:(
kyle

@kyle:心配しないで、私たちは皆間違いを犯します。だから私はSOのwikiっぽいスタイルが好きです。もし私が愚かなタイプミスをした場合、それを見つけてすぐに直してくれる誰かが通常周りにいます。=)
gnovice

1

Matlabはこのためのメカニズムを提供していませんが、inputParserまたは「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

その後、次のように関数で呼び出すことができます。

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

書式設定は、パラメータ名からデフォルト値まで読み取ることができる規則です。getargs()を拡張して、オプションのパラメーター・タイプ指定(エラー検出または暗黙の変換用)および引数カウントの範囲を指定できます。

このアプローチには2つの欠点があります。まず、処理速度が遅いため、ループで呼び出される関数には使用しないでください。次に、Matlabの関数ヘルプ(コマンドラインでのオートコンプリートヒント)は、varargin関数では機能しません。しかし、それはかなり便利です。


0

parseparamsコマンドをmatlabで使用したい場合があります。使用法は次のようになります。

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

たとえばf(2,4,'c',3)、パラメータcを3にします。


0

オクターブを使用する場合は、このようにすることができますが、残念ながら、MATLABはこの可能性をサポートしていません

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

ドキュメントから取得)


0

私はこれをもう少しオブジェクト指向の方法で行うのが好きです。wave()を呼び出す前に、いくつかの引数を構造体内に保存します。パラメータと呼ばれるもの:

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

次に、wave関数内で、構造体パラメーターに「フラグ」と呼ばれるフィールドが含まれているかどうかを確認し、含まれている場合は、その値が空でないかどうかを確認します。次に、以前に定義したデフォルト値、またはパラメータ構造体の引数として指定された値に8を割り当てます。

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

これにより、指定された引数の順序に依存しないため、多数の引数の処理が容易になります。とは言っても、後で関数のシグネチャを変更する必要がないため、後で引数を追加する必要がある場合にも役立ちます。


名前と値のペアのMATLAB標準に従っていないのはなぜですか?wave(a,b,'flag',42,'fTrue',1)
クリスLuengo

これは確かにオプションでもあり、特にパラメーターが少ない場合はそうです。ただし、多数の名前と値のペアでwave()を呼び出すと、コードが読みにくくなる可能性があります。したがって、特定の入力を構造体にグループ化することを好むことがよくあります。
CheshireCat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.