Main Content

コンパイル時の再帰限界値に達する

問題

次のようなメッセージが表示されます。

コンパイル時の再帰限界値に達しました。関数 'foo' の入力 #1 
のサイズまたはタイプは呼び出しごとに変化する場合があります。
コンパイル時の再帰限界値に達しました。関数 'foo' の入力 #1 
の値は呼び出しごとに変化する場合があります。

原因

コンパイル時の再帰により、コード ジェネレーターは生成されたコードで再帰関数を生成せずに、複数のバージョンの再帰関数を生成します。これらのバージョンは、関数の特殊化として知られています。関数の特殊化の数が限界値に達するため、コード ジェネレーターは MATLAB® コードで再帰関数にコンパイル時の再帰を使用できません。

解決法

この問題を解決するには、次のいずれかの解決法を試します。

実行時の再帰の強制

  • 次のメッセージが表示された場合:

    コンパイル時の再帰限界値に達しました。関数 'foo' の入力 #1 
    の値は呼び出しごとに変化する場合があります。

    使用する解決法:

    入力値を非定数として処理することで、実行時の再帰を強制.

  • 次のメッセージが表示された場合:

    コンパイル時の再帰限界値に達しました。関数 'foo' の入力 #1 
    のサイズまたはタイプは呼び出しごとに変化する場合があります。

    コード生成レポートで、関数の特殊化を確認します。関数の特殊化のたびに引数のサイズが変わっていることが確認できた場合は、次の解決法を試してください。

    入力を可変サイズにすることで実行時の再帰を強制.

入力値を非定数として処理することで、実行時の再帰を強制

次の関数を考えてみます。

function y = call_recfcn(n)
A = ones(1,n);
x = 100;
y = recfcn(A,x);
end

function y = recfcn(A,x)
if size(A,2) == 1 || x == 1
    y = A(1);
else
    y = A(1)+recfcn(A(2:end),x-1);
end
end

recfcn への 2 番目の入力には定数値 100 があります。コード ジェネレーターは、再帰的な呼び出しの数は有限であることを判定し、recfcn のコピーを 100 個作成しようとします。特殊化の数がコンパイル時の再帰限界値を超過します。実行時の再帰を強制的に行うには、coder.ignoreConst を使用して 2 番目の入力を非定数値として処理するようにコード ジェネレーターに指示します。

function y = call_recfcn(n)
A = ones(1,n);
x = coder.ignoreConst(100);
y = recfcn(A,x);
end

function y = recfcn(A,x)
if size(A,2) == 1 || x == 1
    y = A(1);
else
    y = A(1)+recfcn(A(2:end),x-1);
end
end

コード ジェネレーターが再帰呼び出しの数が有限であると判定できない場合、ランタイム再帰関数を生成します。

入力を可変サイズにすることで実行時の再帰を強制

次の関数を考えてみます。

function z = call_mysum(A)
%#codegen
z = mysum(A);
end

function y = mysum(A)
coder.inline('never');
if size(A,2) == 1
    y = A(1);
else
    y = A(1)+ mysum(A(2:end));
end
end

mysum への入力が固定サイズの場合、コード ジェネレーターはコンパイル時の再帰を使用します。A が十分に大きい場合、関数の特殊化の数はコンパイル時の制限を超過します。コード ジェネレーターで実行時変換を使用するには、coder.varsize を使用して mysum への入力を可変サイズにします。

function z = call_mysum(A)
%#codegen
B = A;
coder.varsize('B');
z = mysum(B);
end

function y = mysum(A)
coder.inline('never');
if size(A,2) == 1
    y = A(1);
else
    y = A(1)+ mysum(A(2:end));
end
end

コンパイル時の再帰限界値を増やす

コンパイル時の再帰限界値の既定値 50 は、コンパイル時の再帰を必要とするほとんどの再帰関数に対して十分な値です。通常、この限界値を増やしても問題は解決されません。ただし、再帰呼び出しの数が確認可能で、コンパイル時の再帰が必要な場合は、限界値を増やします。たとえば、以下の関数を考えます。

function z = call_mysum()
%#codegen
B = 1:125;
z = mysum(B);
end

function y = mysum(A)
coder.inline('never');
if size(A,2) == 1
    y = A(1);
else
    y = A(1)+ mysum(A(2:end));
end
end

コード ジェネレーターが関数 mysum のコピーを 125 個生成していることが確認できます。この場合、コンパイル時の再帰が必要であれば、コンパイル時の再帰限界値を 125 まで増やします。

コンパイル時の再帰限界値を増やすには、次の操作を実行します。

  • コマンド ラインを使用して、コード生成構成オブジェクトで、CompileTimeRecursionLimit 構成パラメーターの値を増やす。

  • MATLAB Coder™ アプリで、[コンパイル時の再帰限界値] 設定の値を増やす。

関連するトピック