matlab-solve-optimization について
MATLABの最適化を、問題の定式化からソルバー選択、設定、結果検証まで案内するスキルです。MathWorksの最適化ツールで数値最適化のワークフローを作成またはデバッグするユーザー向けです。
主な機能
- 01最適化問題の分類と定式化
- 02問題構造に応じたソルバー選択
- 03ソルバーオプションの設定と確認
- 04勾配と初期実行可能性の確認
- 05結果の検証と収束の診断
活用シーン
- 01制約付きモデルのソルバー選択
- 02収束失敗や不良結果のデバッグ
- 03最適化前の勾配確認
- 04解と制約充足の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-solve-optimizationインストール後、Claude Code で/matlab-solve-optimizationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
manifest.yamlreferences/classify.mdfcn2optimexpr-guide.mdimproving-results.mdperformance-levers.mdproblem-based-guide.mdsolver-tuning.mdvalidation-checklist.md詳細
MATLAB 最適化ワークフロー
問題の分類、定式化、ソルバーの選択と設定、結果の検証まで、最適化のライフサイクル全体を案内します。
使用する場面
- MATLAB で最適化問題(変数、目的関数、制約)を定義している場合
optimproblem、optimvar、optimconstr、optimexpr、またはfcn2optimexprについて質問している場合- ソルバーの選択や設定(
optimoptions、アルゴリズムの選択、調整)を行っている場合 - 結果の解釈、収束のデバッグ、または exitflag の確認を行っている場合
- 問題ベースとソルバーベースのどちらのアプローチを使うか検討している場合
- 決定変数や制約に対する for ループを使って最適化コードを書いている場合
使用しない場面
- 数値最適化ソルバーを必要としない問題(例:配列やテーブルから最小値を見つけること)を解こうとしている場合
- 最適化以外の MATLAB コード(データ解析、プロット、信号処理)を扱っている場合
- サードパーティ製の最適化ツールボックス(MathWorks 製ではない)を使用している場合
solve(eqns, vars)を使った記号方程式、ODE システム、または線形システムの求解(A\b)を行っている場合
ステージ 1:分類と定式化
1.1 問題を分類する
定式化の前に、問題のクラスを特定してください。これは、使用するソルバー、保証できる結果(大域的か局所的か)、および汎用的な手法の代わりに特定分野向けのツールを使うべきかどうかを決める要素です。
クラス→ソルバー→保証の対応表、凸性の簡易チェック、「より簡単な隠れたクラス」を見つけるヒューリスティクスについては、references/classify.md を参照してください。主な対応事項:
optimproblemに進む前に、目的に特化したツールがないか確認する- 隠れた、より簡単なクラスに注意する(NLP に見せかけた二乗和、見落とされた線形構造など)
- QP では
eig(H)を確認する。非凸 QP はquadprogを信頼して使用できません - 隠れた非滑らかさに注意する:
max、min、abs、sort、if/分岐、または 2 乗ユークリッドノルム以外のノルム
1.2 アプローチを選択する
読みやすい定義、N 次元モデリング、すべての LP、QP、錐計画問題、混合整数問題(係数がすでに行列・ベクトル形式である場合を除く)では、デフォルトで問題ベースを使用してください。問題ベースでは自動微分が行われ、誤りも起こりにくくなります。
AD が阻まれる場合(例:目的関数内の ode45)でも、fcn2optimexpr で関数をブラックボックスとしてラップできます。そのため、問題ベースは引き続き有用です。
次のいずれかに該当する場合に限り、ソルバーベースに切り替えてください。
| ソルバーベースを使用する場面... | 理由 |
|---|---|
ソルバー API への単純な対応付け — ベクトル x が 1 つで、正確な勾配・ヘッセ行列を備えた目的関数が事前にコーディングされている | 抽象化による利点がなく、ソルバーベースのほうが直接的です |
| 問題ベースの式を構築するオーバーヘッドが計算を支配している | トレース/変換のオーバーヘッドを避けられます |
問題ベースで公開されていないソルバー機能(CheckpointFile、正確なヘッセ行列、カスタム OutputFcn)が必要 | ソルバーベースの呼び出しでのみ利用できます |
| 組み込み展開用の C コード生成が必要 | 問題ベースはコード生成をサポートしていません |
アプローチ間の変換: prob2struct(prob) は、展開またはパフォーマンス向上のために、問題ベースの形式をソルバーベースの形式に変換します。
参考資料:
- 問題ベース:references/problem-based-guide.md
- ソルバーベース(クラス→ソルバーの対応付け):references/classify.md
1.3 問題を定式化する
問題ベースの標準テンプレート:
% 1. Define decision variables
x = optimvar("x", N, LowerBound=lb, UpperBound=ub);
% 2. Create problem
prob = optimproblem("Objective", sum(x,"all"));
% 3. Add constraints
prob.Constraints.linear = A*x <= b;
prob.Constraints.nonlinear = fcn2optimexpr(@myNonlinFcn, x) <= rhs;
% 4. Set initial guess (must be struct with field names matching optimvar names)
x0.x = initialValues;
% 5. Solve
[sol, fval, exitflag, output] = solve(prob, x0);
ソルバーベースとの主な違い:
- 初期値は構造体ではなく、数値ベクトルです
- 変数のインデックスは手動で管理します(フラットなベクトル
x) - パフォーマンスを最大限に高めるには、勾配を手動で指定します(
SpecifyObjectiveGradient=true) - 線形/二次ソルバーでは、係数行列を明示的に指定する必要があります
1.4 初期点で検証する
ソルバーを呼び出す前に、x0 で目的関数と制約を評価し、符号・サイズ・NaN のエラーを早期に検出します。
% Problem-based
fval0 = evaluate(prob.Objective, x0);
assert(isfinite(fval0), 'Objective is not finite at x0');
infeas0 = infeasibility(prob.Constraints, x0);
fprintf('Max infeasibility at x0: %.3e\n', max(infeas0));
ソルバーベースの場合は、fun(x0) と nonlcon(x0) を直接呼び出し、出力が有限値で、サイズが正しいことを確認します。勾配を指定している場合は、この時点で checkGradients を実行します。
ステージ 2:ソルバーを選択して設定する
2.1 最も適したソルバーを選択する
問題の構造に合った、最も適したソルバーを選択します。 より具体的なソルバーが適用できる場合は、fmincon やヒューリスティックな大域ソルバーをデフォルトで選択しないでください。
主な選択ルール:
- 常に次の優先順位に従います:
linprog>quadprog>coneprog>lsqlin>lsqnonlin>fmincon> 大域ソルバー - Optimization Toolbox がインストールされている場合は、常に
fminsearchよりfminuncを優先します - 最小二乗問題では、常に
fminconよりlsqnonlin/lsqcurvefitを優先します - 境界または線形制約がある線形最小二乗問題では、常に
lsqnonlinよりlsqlinを優先します - 勾配を利用できない、または信頼できない場合で、問題の計算コストが極端に高くないときは
patternsearchを使用します - 各評価に 15~20 秒以上かかる場合は
surrogateoptを使用します - ほぼ線形な MIP では、線形化して Global Optimization ソルバーを呼び出すのではなく、
intlinprogを使用します - ユニットコミットメント/バイナリ運転モードでは、
intlinprogを使用する混合整数問題として扱います
クラスからソルバーへの完全な対応表については、references/classify.md を参照してください。
2.2 オプションを確認する — 推測しない
オプションを使用する前に、必ずソルバーオプションが有効であることを確認してください。 オプションは MATLAB のリリースによって変わるため、実在しないオプションを指定すると実行時エラーが発生します。
% Verify options for a solver
opts = optimoptions('solvername')
オプションのコードを記述する前に、optimoptions('solvername') を実行して、ユーザーがインストールしているバージョンで有効なオプションをすべて確認します。
2.3 勾配を検証する(指定している場合)
解析的勾配を指定している場合(SpecifyObjectiveGradient=true)、求解前に検証します。
[valid, err] = checkGradients(@myObjective, x0, Display="on");
制約勾配の場合:checkGradients(@myConstraints, x0, IsConstraint=true)。
2.4 並列化する(計算コストが高い場合)
ソルバーが UseParallel に対応しており、Parallel Computing Toolbox が利用可能な場合:
ver('parallel') % Check for PCT
options = optimoptions('solvername', UseParallel=true);
UseParallel に対応するソルバー:fmincon、fminunc、lsqnonlin、lsqcurvefit、patternsearch、surrogateopt、ga、particleswarm、paretosearch、gamultiobj。
次のソルバーでは UseParallel を提案しないでください:quadprog、intlinprog、fminsearch、linprog、lsqlin。
2.5 パフォーマンス(正しさを確認した後)
求解結果は正しいものの遅すぎる場合は、references/performance-levers.md を参照してください。主な調整項目:解析的勾配、疎性パターン、ウォームスタート、コード生成。ステージ 3 で正しさを確認した後にのみ適用し、パフォーマンスを変更した場合は必ず再検証してください。
参考: ソルバーごとのアルゴリズムと調整方法については、references/solver-tuning.md を参照してください。
ステージ 3:結果を検証する
3.1 基本検証(必ず含める)
ソルバーを呼び出すコードを書く際は、毎回、基本的な出力検証を追加してください。
[sol, fval, exitflag, output] = solve(prob, x0);
% Check convergence
if exitflag > 0
fprintf('Optimization converged: %s\n', output.message);
else
warning('Optimization did not converge (exitflag = %d): %s\n', exitflag, output.message);
end
% Report key metrics
fprintf('Objective value: %.6f\n', fval);
fprintf('Iterations: %d\n', output.iterations);
if isfield(output, 'constrviolation')
fprintf('Constraint violation: %d\n', output.constrviolation);
end
ソルバーごとの exitflag の意味の詳細については、references/validation-checklist.md を参照してください。
3.2 拡張検証
制約違反(問題ベース):
[allsat, sat] = issatisfied(prob, sol);
if ~allsat
conNames = fieldnames(prob.Constraints);
for i = 1:numel(conNames)
infeas = infeasibility(prob.Constraints.(conNames{i}), sol);
if any(infeas > 0)
fprintf('Constraint "%s" violated by %.3e\n', conNames{i}, max(infeas));
end
end
end
最適性条件(勾配ベースのソルバーのみ — patternsearch、ga、particleswarm、surrogateopt では省略):
if isfield(output, 'firstorderopt')
fprintf('First-order optimality: %.6e\n', output.firstorderopt);
if output.firstorderopt > 1e-3
warning('First-order optimality measure is large — solution may not be optimal.\n');
end
end
3.3 失敗した解や品質の低い解のデバッグ
exitflag <= 0 の場合や収束が不十分な場合は、references/improving-results.md の結果改善チェックリストに従ってください。
- 定式化を確認する — 制約は実行可能ですか?境界は整合していますか?目的関数は x0 で適切に定義されていますか?
- スケーリングを確認する — 変数を O(1) にスケーリングします。目的関数と制約の桁が大きく異なる場合は再スケーリングします。有限差分勾配が不正確な場合は
FiniteDifferenceType='central'を使用します。 - 別のアルゴリズムを試す —
options.Algorithmを変更し、MaxIterations/MaxFunctionEvaluationsを増やし、許容誤差を調整し、ヒューリスティックソルバーではHybridFcnを設定します。 - 別の初期点を試す — 大域最適化には、
MultiStart、GlobalSearch、またはsurrogateopt/gaを使用します。
デバッグの原則:
- まずは最小規模で試します。 変数を 2~3 個に減らします。おもちゃの問題ならバグの特定に数分ですが、フルスケールでは数時間かかります。
- 症状に基づいて、一度に 1 つだけ変更します。
- 中断して相談する基準を設けます。 改善がないまま 3 回を超えて試行した場合、診断結果が変わらないオプション調整が 2 回を超えた場合、またはおもちゃの問題でも x0 で有限の目的関数値を得られない場合は、コーディングを中断してユーザーに相談します。
3.4 アプリケーション固有の可視化
| 問題領域 | 推奨プロット |
|---|---|
| 最適制御/ナビゲーション | 時間に対する状態軌跡、制御入力プロファイル、位相図 |
| スケジューリング/割り当て | ガントチャート、時間経過に伴うリソース使用率 |
| 設計最適化 | 最適解をマークした等高線図、感度プロット |
| パラメーター推定/フィッティング | 残差プロット、データとフィッティング済み曲面 |
| ポートフォリオ/配分 | 配分の棒グラフ、効率的フロンティアのプロット |
注意点
定式化
- 初期推定値は、フィールド名が
optimvarの名前と完全に一致する構造体でなければなりません。 フラットなベクトルは使用しないでください。 - 問題ベースのオプションで
SpecifyObjectiveGradientやSpecifyConstraintGradientを設定しないでください。 勾配は AD が内部で処理します。 - 多次元の問題には N 次元の
optimvarを使用します。 ループ内でスカラー変数を作成しないでください。 - 制約配列は
optimconstr(N)で事前割り当てします。 ループ内で連結しないでください。 - 関数ごとに
fcn2optimexprを呼び出すのは 1 回だけにし、ループ内では呼び出さないでください。 references/fcn2optimexpr-guide.md を参照してください。 - トレース対象の関数内で事前割り当てを行うときは、AD の型を維持するために
"like"を使用します。zeros(n,1,"like",x)のように指定します。
ソルバーの設定
- 記憶を頼りにオプション名を推測しないでください。 必ず
optimoptions('solvername')で確認してください。 patternsearchのMeshToleranceを過度に厳しく設定しないでください。- 早期停止のために、
intlinprogのAbsoluteGapTolerance/RelativeGapToleranceを大きく設定しないでください。 時間制限/ノード制限を使用してください。 - 許容誤差は機械イプシロンを十分に上回る値にします。 特別な要件がない限り、
1e-6~1e-8の範囲を使用してください。
検証
- 制約なしソルバーでは
output.constrviolationは存在しません。 必ずisfieldで確認してください。 - 導関数不要のソルバーでは
output.firstorderoptを確認しないでください。 代わりにソルバー固有の指標(output.meshsize、output.stallgenerationsなど)を確認してください。 infeasibility()は問題全体ではなく、個々の制約に対して動作します。 全体を確認するにはissatisfied(prob, sol)を使用してください。fminconでexitflag <= 0の場合は、output.bestfeasibleを確認してください。 新しい求解の開始点として使用します。
規約
- 特定の阻害要因がある場合を除き、問題ベースのアプローチをデフォルトとします。
- ベクトル化が可能な場合は、常にループよりもベクトル化を優先します。
- 複雑なロジックを
fcn2optimexprでラップする場合は、ループ内で呼び出すのではなく、単一のヘルパー関数にまとめます。 - 初期値の設定を必ず示します。
- ユーザーが提供する関数に依存するコードブロックには、テンプレートと明記します。
- 調整オプションを提案する場合は、トレードオフ(速度と精度)を説明します。
- 過剰な調整は避けます。単純な問題や小規模な問題では、デフォルト設定で十分なことがほとんどです。
- ソルバーを呼び出すコードを書く場合は、必ず基本的な検証(exitflag の確認)を含めます。
- デバッグ時は、アルゴリズムを変更する前に、定式化とスケーリングを確認します。
Copyright 2026 The MathWorks, Inc.