別の関数を引数として取るMATLABの関数があります。渡すことができる区分的インライン関数をどうにかして定義したいと思います。これはMATLABでどういうわけか可能ですか?
編集:私が表現したい関数は次のとおりです。
f(x) = { 1.0, 0.0 <= x <= 0.5,
-1.0, 0.5 < x <= 1.0
where 0.0 <= x <= 1.0
[0, 0.5, 1] の 3 つのブレーク ポイントを持つ区分関数を実際に定義しました。ただし、ブレークの外側で関数の値を定義していません。(ちなみに、ここで「ブレーク」という用語を使用しました。これは、単純な形式のスプライン、区分定数スプラインを実際に定義しているためです。また、スプラインの世界でよく使われるもう 1 つの単語であるノットという用語も使用した可能性があります。 )
[0,1] の外で関数を評価しないことが絶対にわかっている場合は、問題はありません。したがって、x = 0.5 に 1 つのブレーク ポイントを持つ区分関数を定義するだけです。あなたのような区分定数関数を定義する簡単な方法は、論理演算子を使用することです。したがって、テスト (x > 0.5) は、0 または 1 のいずれかの定数を返します。その結果をスケーリングおよび変換することにより、目的の関数を簡単に生成できます。
constfun = @(x) (x > 0.5)*2 - 1;
インライン関数も同様のことを行いますが、インライン関数は無名関数に比べて非常に遅くなります。匿名フォームの使用を強くお勧めします。テストとして、これを試してください:
infun = inline('(x > 0.5)*2 - 1','x');
x = 0:.001:1;
tic,y = constfun(x);toc
Elapsed time is 0.002192 seconds.
tic,y = infun(x);toc
Elapsed time is 0.136311 seconds.
はい、インライン関数は、匿名フォームよりも実行に非常に時間がかかりました。
ここで使用した単純な区分定数形式の問題は、より多くのブレーク ポイントがある場合に拡張するのが難しいことです。たとえば、ポイントがどの間隔に収まったかに応じて 3 つの異なる値をとる関数を定義したいとします。これは、テストをクリエイティブに使用し、慎重にシフトおよびスケーリングすることでも実行できますが、厄介なことになる可能性があります。たとえば、以下を返す区分関数をどのように定義しますか?
-1 when x < 0,
2 when 0 <= x < 1,
1 when 1 <= x
1 つの解決策は、単位Heaviside関数を使用することです。まず、基本単位ヘヴィサイド関数を定義します。
H = @(x) (x >= 0);
区分関数は、H(x) から導出されます。
P = @(x) -1 + H(x)*3 + H(x-1)*(-1);
P(x) には 3 つのピースがあることを確認してください。最初の項は、最初のブレーク ポイントより下の x に対して何が起こるかです。次に、ゼロより上で有効になるピースを追加します。最後に、3 番目のピースは上記の x == 1 に別のオフセットを追加します。これは簡単にプロットできます。
ezplot(P,[-3,3])
より洗練されたスプラインは、最初から簡単に生成できます。この構成を再びスプラインと呼んでいることを確認してください。本当に、これは私たちがリードしている可能性がある場所です。実際、これはこれが導くところです。スプラインは区分関数であり、ノットまたはブレーク ポイントのリストで慎重に結び付けられます。特にスプラインには多くの場合、連続性の次数が指定されているため、たとえば、3 次スプラインはブレーク全体で 2 回微分可能 (C2) になります。C1 関数のみである区分的 3 次関数もあります。ここまでで要点は、任意の区分関数を作成するための単純な開始点を説明したことです。多項式スプラインでは非常にうまく機能しますが、これらの関数の係数を選択するには少し数学が必要になる場合があります。
この関数を作成する別の方法は、明示的な区分多項式として作成することです。MATLAB には、あまり知られていない関数 mkpp があります。これを試してみてください...
pp = mkpp([0 .5 1],[1;-1]);
スプライン ツールボックスがあれば、fnplt がこれを直接プロットします。その TB を持っていないと仮定すると、次のようにします。
ppfun = @(x) ppval(pp,x);
ezplot(ppfun,[0 1])
mkpp 呼び出しを振り返ってみると、やはり単純です。最初の引数は、曲線のブレーク ポイントのリストです (ROW ベクトルとして)。2 番目の引数は COLUMN ベクトルで、ブレーク間のこれら 2 つの定義された間隔で曲線が取る区分定数値を持ちます。
数年前、別のオプションpiecewise_evalを投稿しました。これは、MATLAB Central ファイル交換からダウンロードできます。これは、ユーザーが区分関数を純粋にブレーク ポイントのリストとして指定できるようにする関数であり、これらのブレーク間の関数部分も一緒に指定できます。したがって、x = 0.5 で 1 つのブレークを持つ関数の場合、次のようにします。
fun = @(x) piecewise_eval(x,0.5,{1,-1});
3 番目の引数が各セグメントで使用される値を提供することを確認してください。ただし、これらの部分は純粋に定数関数である必要はありません。関数が対象区間外の NaN を返すようにしたい場合、これも簡単に実現できます。
fun = @(x) piecewise_eval(x,[0 0.5 1],{NaN,1,-1,NaN});
このかなり長いエクスカーションのすべてでの私のポイントは、区分関数とは何か、および MATLAB で区分関数を作成するいくつかの方法を理解することです。
残念ながら、MATLAB にはこのようなことを簡単にする三項演算子はありませんが、gnovice のアプローチを少し拡張するために、次のような無名関数を作成できます。
fh = @(x) ( 2 .* ( x <= 0.5 ) - 1 )
一般に、無名関数はインライン関数オブジェクトよりも強力で、クロージャなどを作成できます。
(無名関数ではなく) インライン関数を本当に作成したい場合は、おそらく次の方法が最も簡単な方法です。
f = inline('2.*(x <= 0.5)-1');
ただし、他の回答で指摘されているように、無名関数はより一般的に使用され、より効率的です。
f = @(x) (2.*(x <= 0.5)-1);
その問題を解決する必要がありましたが、最も簡単な方法は無名関数を使用することだと思います。区分関数があるとします。
when x<0 : x^2 + 3x
when 0<=x<=4: e^x
when x>4 : log(x)
まず、区分領域ごとに論理マスクを定義します。
PIECE1 = @(x) x<0
PIECE2 = @(x) x>=0 & x<=4
PIECE3 = @(x) x>4
次に、それらをすべてまとめます。
f = @(x) PIECE1(x).*(x.^2+3*x) + PIECE2(x).*exp(x) + PIECE3(x).*log(x)
x = -10:.1:10
figure;
plot(x,f(x))