mcpField
M
matlab-solve-optimization

matlab-solve-optimization

github.com/matlabデータ・データベース1.2k58 回インストール1 日前に更新
リポジトリ

matlab-solve-optimization について

MATLABの最適化を、問題の定式化からソルバー選択、設定、結果検証まで案内するスキルです。MathWorksの最適化ツールで数値最適化のワークフローを作成またはデバッグするユーザー向けです。

主な機能

  1. 01最適化問題の分類と定式化
  2. 02問題構造に応じたソルバー選択
  3. 03ソルバーオプションの設定と確認
  4. 04勾配と初期実行可能性の確認
  5. 05結果の検証と収束の診断

活用シーン

  1. 01制約付きモデルのソルバー選択
  2. 02収束失敗や不良結果のデバッグ
  3. 03最適化前の勾配確認
  4. 04解と制約充足の検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-solve-optimization

インストール後、Claude Code で/matlab-solve-optimizationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

manifest.yaml
references/
classify.md
fcn2optimexpr-guide.md
improving-results.md
performance-levers.md
problem-based-guide.md
solver-tuning.md
validation-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) は、展開またはパフォーマンス向上のために、問題ベースの形式をソルバーベースの形式に変換します。

参考資料:

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 の結果改善チェックリストに従ってください。

  1. 定式化を確認する — 制約は実行可能ですか?境界は整合していますか?目的関数は x0 で適切に定義されていますか?
  2. スケーリングを確認する — 変数を O(1) にスケーリングします。目的関数と制約の桁が大きく異なる場合は再スケーリングします。有限差分勾配が不正確な場合は FiniteDifferenceType='central' を使用します。
  3. 別のアルゴリズムを試す — options.Algorithm を変更し、MaxIterations/MaxFunctionEvaluations を増やし、許容誤差を調整し、ヒューリスティックソルバーでは HybridFcn を設定します。
  4. 別の初期点を試す — 大域最適化には、MultiStart、GlobalSearch、または surrogateopt/ga を使用します。

デバッグの原則:

  • まずは最小規模で試します。 変数を 2~3 個に減らします。おもちゃの問題ならバグの特定に数分ですが、フルスケールでは数時間かかります。
  • 症状に基づいて、一度に 1 つだけ変更します。
  • 中断して相談する基準を設けます。 改善がないまま 3 回を超えて試行した場合、診断結果が変わらないオプション調整が 2 回を超えた場合、またはおもちゃの問題でも x0 で有限の目的関数値を得られない場合は、コーディングを中断してユーザーに相談します。
3.4 アプリケーション固有の可視化
問題領域推奨プロット
最適制御/ナビゲーション時間に対する状態軌跡、制御入力プロファイル、位相図
スケジューリング/割り当てガントチャート、時間経過に伴うリソース使用率
設計最適化最適解をマークした等高線図、感度プロット
パラメーター推定/フィッティング残差プロット、データとフィッティング済み曲面
ポートフォリオ/配分配分の棒グラフ、効率的フロンティアのプロット

注意点

定式化
  1. 初期推定値は、フィールド名が optimvar の名前と完全に一致する構造体でなければなりません。 フラットなベクトルは使用しないでください。
  2. 問題ベースのオプションで SpecifyObjectiveGradient や SpecifyConstraintGradient を設定しないでください。 勾配は AD が内部で処理します。
  3. 多次元の問題には N 次元の optimvar を使用します。 ループ内でスカラー変数を作成しないでください。
  4. 制約配列は optimconstr(N) で事前割り当てします。 ループ内で連結しないでください。
  5. 関数ごとに fcn2optimexpr を呼び出すのは 1 回だけにし、ループ内では呼び出さないでください。 references/fcn2optimexpr-guide.md を参照してください。
  6. トレース対象の関数内で事前割り当てを行うときは、AD の型を維持するために "like" を使用します。 zeros(n,1,"like",x) のように指定します。
ソルバーの設定
  1. 記憶を頼りにオプション名を推測しないでください。 必ず optimoptions('solvername') で確認してください。
  2. patternsearch の MeshTolerance を過度に厳しく設定しないでください。
  3. 早期停止のために、intlinprog の AbsoluteGapTolerance/RelativeGapTolerance を大きく設定しないでください。 時間制限/ノード制限を使用してください。
  4. 許容誤差は機械イプシロンを十分に上回る値にします。 特別な要件がない限り、1e-6~1e-8 の範囲を使用してください。
検証
  1. 制約なしソルバーでは output.constrviolation は存在しません。 必ず isfield で確認してください。
  2. 導関数不要のソルバーでは output.firstorderopt を確認しないでください。 代わりにソルバー固有の指標(output.meshsize、output.stallgenerations など)を確認してください。
  3. infeasibility() は問題全体ではなく、個々の制約に対して動作します。 全体を確認するには issatisfied(prob, sol) を使用してください。
  4. fmincon で exitflag <= 0 の場合は、output.bestfeasible を確認してください。 新しい求解の開始点として使用します。

規約

  • 特定の阻害要因がある場合を除き、問題ベースのアプローチをデフォルトとします。
  • ベクトル化が可能な場合は、常にループよりもベクトル化を優先します。
  • 複雑なロジックを fcn2optimexpr でラップする場合は、ループ内で呼び出すのではなく、単一のヘルパー関数にまとめます。
  • 初期値の設定を必ず示します。
  • ユーザーが提供する関数に依存するコードブロックには、テンプレートと明記します。
  • 調整オプションを提案する場合は、トレードオフ(速度と精度)を説明します。
  • 過剰な調整は避けます。単純な問題や小規模な問題では、デフォルト設定で十分なことがほとんどです。
  • ソルバーを呼び出すコードを書く場合は、必ず基本的な検証(exitflag の確認)を含めます。
  • デバッグ時は、アルゴリズムを変更する前に、定式化とスケーリングを確認します。

Copyright 2026 The MathWorks, Inc.

コメント