線形最適化
はじめに
線形最適化問題とは,目的関数と制約条件がすべて線形である問題を言う.
Wolfram言語には実数変数を持つ線形最適化問題を解くためのアルゴリズム群があり,LinearOptimization,FindMinimum,FindMaximum,NMinimize,NMaximize,Minimize,Maximizeでアクセスできる.LinearOptimizationを使うと,線形最適化アルゴリズムに直接アクセスできる.これは使用するメソッドを最も柔軟に指定することができ,大規模な問題に最も効率的である.FindMinimum,FindMaximum,NMinimize,NMaximize,Minimize,Maximizeは方程式および不等式の形式での線形最適化問題を解くのに便利である.
Minimize[{x + 2 y, -5x + y == 7 && x + y ≥ 26 && x ≥ 3 && y ≥ 4}, {x, y}]NMinimize[{x + 2 y, -5x + y == 7 && x + y ≥ 26 && x ≥ 3 && y ≥ 4}, {x, y}]LinearOptimization[x + 2y, {-5x + y == 7, x + y >= 26, x >= 3, y >= 4}, {x, y}]LinearOptimization関数
LinearOptimization は線形最適化の主要関数であり,使用するメソッドの指定が最も柔軟にでき,大規模な問題に最も効率的である.
オプション名
|
デフォルト値
| |
| Method | Automatic | 線形最適化問題を解くのに使用するメソッド |
| Tolerance | Automatic | 収束の許容誤差 |
| MaxIterations | Automatic | 使用する反復の最大回数 |
| PerformanceGoal | $PerformanceGoal | 最適化を試みる精度 |
| WorkingPrecision | Automatic | 内部計算で使用する精度 |
LinearOptimizationのオプション
Methodオプションは,線形最適化問題を解くアルゴリズムを指定する.これで使用できる値はAutomatic,"Simplex","RevisedSimplex","InteriorPoint", "CLP","MOSEK","Gurobi"である.デフォルトはAutomaticであり,問題の大きさと精度に基づいて,他のメソッドの中から自動的に選ばれる.
Toleranceオプションは,収束の許容誤差を指定する.
WorkingPrecision->Automaticにすると,機械精度でしか動作しないメソッドが指定されていない限り,精度は入力引数の精度から自動的に取られる.そのメソッドが指定されている場合は機械精度が使われる.
LinearOptimizationからアクセスできる解の特性は多数ある:
| "PrimalMinimizer" | { | 目的関数を最小化する変数値のリスト |
| "PrimalMinimizerRules" | {v1 | |
| "PrimalMinimizerVector" | x* | |
| "PrimalMinimumValue" | ||
| "DualMaximizer" | ||
| "DualMaximumValue" | 双対最大値 | |
| "DualityGap" | 双対問題の最適値と主問題の最適値の差分(強双対性のため0) | |
| "Slack" | 制約条件緩和ベクトル | |
| "ConstraintSensitivity" | 制約条件摂動への | |
| "ObjectiveVector" | 線形目的ベクトル | |
| "LinearInequalityConstraints" | 線形不等式制約条件行列およびベクトル | |
| "LinearEqualityConstraints" | 線形等式制約条件行列およびベクトル | |
| {"prop1","prop2",...} | | いくつかの解の特性 |
LinearOptimizationの解の特性
例題
内点法とシンプレックス法および/または改訂シンプレックス法との違い
シンプレックス法および改定シンプレックス法は,極小値に達するまで目的関数の継続的に小さい方の値で頂点から頂点へと,制約条件により定義されたポリトープの辺に沿って移動することにより線形最適化問題を解く.これらの関数のWolfram言語の実装では,密な線形代数が使われる.この実装のユニークな点は,厳密・拡張精度問題が解けるという点である.したがって,これらの方法は,非機械数の結果が必要ない,または頂点の解が望まれるような小さいサイズの問題に適している.
線形最適化の内点法は,大まかに言うと,制約条件により定義されたポリトープの内部から反復する.これは非常に速く解に近付くが,シンプレックス・改訂シンプレックス法とは異なり,厳密な解は見付けない.Wolfram言語における内点法の実装では,機械精度の疎な線形代数を使う.よって,大規模の機械精度線形最適化問題では,内点法の方が効率がよいのでこれを使うべきである.
LinearOptimization[-x - y, x + y <= 1, {x, y}, Method -> "InteriorPoint"]LinearOptimization[-x - y, x + y <= 1, {x, y}, Method -> "RevisedSimplex"]m = SparseArray[RandomChoice[{0.1, 0.9} -> {1., 0.}, {50, 200}]];
xi = LinearOptimization[Range[200].x, {m.x0, x0}, x, "PrimalMinimizerVector", Method -> "InteriorPoint"]; //Timingxs = LinearOptimization[Range[200].x, {m.x0, x0}, x, "PrimalMinimizerVector", Method -> "Simplex"]; //TimingRange[200].(xi - xs)二重変数の探索
主問題が…ならば
|
双対問題は…である
|
| 実行可能 | 実行可能 |
| 非有界 | 実行不可能または非有界 |
| 実行不可能 | 非有界または実行不可能 |
両方の問題が実行可能である場合,(P)と(D)の最適値は同じであり,主問題の解
および双対問題の解
に対して次の相補条件が成り立つ.
双対の最大化はLinearOptimizationで"DualMaximizer"特性を使うことで得ることができる.
primal = LinearOptimization[3x + 4y, {x + 2y >= 5, 1 <= x <= 4, 1 <= y <= 4}, {x, y}, {"PrimalMinimizerRules", "DualMaximizer"}]dual = LinearOptimization[-(5Subscript[λ, 1] + Subscript[λ, 2] - 4Subscript[λ, 3] + Subscript[λ, 4] - 4Subscript[λ, 5]), {Subscript[λ, 1] + Subscript[λ, 2] - Subscript[λ, 3] == 3,
2Subscript[λ, 1] + Subscript[λ, 4] - Subscript[λ, 5] == 4, Subscript[λ, 1] >= 0, Subscript[λ, 2] >= 0, Subscript[λ, 3] >= 0, Subscript[λ, 4] >= 0, Subscript[λ, 5] >= 0}, {Subscript[λ, 1], Subscript[λ, 2], Subscript[λ, 3], Subscript[λ, 4], Subscript[λ, 5]}]{3, 4}.{x, y} /. primal[[1]]{5, 1, -4, 1, -4}.{Subscript[λ, 1], Subscript[λ, 2], Subscript[λ, 3], Subscript[λ, 4], Subscript[λ, 5]} /. dualLinearOptimization[3x + 4y, {x + 2y >= 5, 1 <= x <= 4, 1 <= y <= 4}, {x, y}, {"PrimalMinimumValue", "DualMaximumValue"}]pval = LinearOptimization[3x + 4y, {x + 2y >= 5 + 0.001, 1 <= x <= 4, 1 <= y <= 4}, {x, y}, "PrimalMinimumValue"]pval - {3, 4}.{x, y} /. primal[[1]]{a, b} = {{{1, 2}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}}, {-5, -1, 4, -1, 4}};
{p^ * , {Subscript[s, λ], Subscript[s, ν]}} = LinearOptimization[3x + 4y, a.{x, y} + b0, {x, y}, {"PrimalMinimumValue", "ConstraintSensitivity"}]p^ * + Subscript[s, λ].{-0.001, 0, 0, 0, 0}内点法における実行不可能性と非有界性の扱い
主双対内点法は実行可能な問題に対して設計されており,実行不可能/非有界の問題では発散してしまう. その上,現在の実装では発散が実行不可能性によるものか非有界性によるものかを見分けるのは難しい.
LinearOptimization[x + y, {x + y <= 1, x + y >= 2}, {x, y}, Method -> "InteriorPoint"]LinearOptimization[-x - y, {x + y >= 1, x >= 0, y >= 0}, {x, y}, Method -> "InteriorPoint"]LinearOptimization[-x - y, {x + y >= 1, x >= 0, y >= 0}, {x, y}, Method -> "Simplex"]"InteriorPoint"のメソッドオプション
"TreatDenseColumn"は"InteriorPoint"のメソッドオプションであり, 密な列を別々に扱うかどうかを決定する.密な列とは,多くの非零要素を含む制約行列の列のことである.このメソッドのデフォルト値はAutomaticであり,密な列は別々に扱われる.
A = SparseArray[{{i_, i_} -> 1., {i_, 1} -> 1.}, {300, 300}];
c = Table[1, {300}];
b = A.Range[300];{x1 = LinearOptimization[c.x, {A.xb, x0}, x, "PrimalMinimizerVector", Method -> "InteriorPoint"]; // Timing,
x2 = LinearOptimization[c.x, {A.xb, x0}, x, "PrimalMinimizerVector", Method -> {"InteriorPoint", "TreatDenseColumns" -> False}];//Timing}x1.c - x2.c大きいデータをインポートし,大規模問題を解く
線形最適化問題を記述するのによく使われる形式はMPS(数理計画問題)形式である.これは多数のセクションで構成されるテキスト形式である.
方程式のMPSファイルをインポートする
Wolfram言語はMPS形式のファイルをインポートすることができる.MPSデータのImportにより,線形最適化問題はデフォルトで方程式形式で返される.この形式はLinearOptimization,Minimize,NMinimizeを使って解くことができる.
{eqns, vars} = Import["Optimization/Data/afiro.mps"]LinearOptimization[eqns[[1]], Rest[eqns], vars]大規模な問題:行列形式およびベクトル形式でのインポート
大規模な問題の場合,MPSデータファイルをインポートし,行列かベクトルで行列問題を表してからLinearOptimizationを使って解いた方が効率的である.
Import["Optimization/Data/ganges.mps", "Elements"]{c, linIneq, linEq} = Import["Optimization/Data/ganges.mps", "LinearOptimizationData"];x = LinearOptimization[c, linIneq, linEq];c.xp = Import["Optimization/Data/ganges.mps", "ConstraintMatrix"]自由書式のMPSファイル
標準的なMPS形式のファイルでは固定書式が使われており,各欄の文字の位置が厳密に決まっている.しかし,モデリングシステムの中には自由書式のMPSファイルを出力するものもあり,欄の位置が自由である.後者のファイルでは,Importでオプション"FreeFormat"->Trueを指定することができる.
txt = "NAME TESTPROB
ROWS
N COST
L CON1
G CON2
E CON3
COLUMNS
x COST 1 CON1 2
x CON2 3
y COST 4 CON1 5
y CON3 6
Z COST 7 CON2 8
Z CON3 9
RHS
RHS1 CON1 10 CON2 11
RHS1 CON3 12
BOUNDS
UP BND1 x 13
LO BND1 y 14
UP BND1 y 15
ENDATA
";file = Close[OpenWrite[]];
Export[file, txt, "Text"];Import[file, "MPS", "FreeFormat" -> True]線形最適化テスト問題
NetLib線形最適化テスト問題はすべてExampleData関数からアクセスすることができる.
ExampleData["LinearOptimization"]afiroData = ExampleData[{"LinearOptimization", "afiro"}]LinearOptimization@@afiroDataExampleData[{"LinearOptimization", "afiro"}, "Properties"]afiroEqns = ExampleData[{"LinearOptimization", "afiro"}, "Equations"]LinearOptimization[Sequence@@afiroEqns[[1]], afiroEqns[[2]]]線形最適化の応用例題
L1ノルム最小化
{input, output} = IconizedObject[«Block»];
dataplot = ListPlot[output, PlotRange -> All]Clear[a, b, s, x];
res = LinearOptimization[Total[s], {a == input, b == output, -sa.x - bs}, {x, s}]Show[ dataplot, Plot[Evaluate[x.{1, t} /. res], {t, 1, 30}]]line = Fit[output, {1, t}, t]Show[ dataplot, Plot[Evaluate[{x.{1, t} /. res, line}], {t, 1, 30}]]最適なトラスの設計
この例題は[2]から採用したものである.この問題の目的は,負荷をサポートするのにできるだけ少ない材料を使ってアンカーを設計するというものである.
この問題は,まずノードとリンクを使って離散化し,シミュレーションを行うことによりモデル化することができる.モデル化の過程は以下の図で示す.ここで7×10のノードを持つ格子が生成される.それぞれのノードはマンハッタン距離が3以下である他のすべてのノードへのリンクにより接続される.赤い3つのノードは壁に固定されるもので,他のノードはすべて圧縮力および張力のバランスが取れていなければならない.
各リンクは厚みのある硬い棒を表しており,重さはそれにかかる力と長さに比例している.目標は,使用される材料を最小化することである.
したがって,これは数学的に線形の制約付き最小化問題であり,目的関数が線形関数の絶対値の和である.
目的関数の絶対値
は,
を圧縮力と張力(ともに非負)に分けて置き換えることができる.ここで
をリンクの集合,
をノードの集合,
をノード
と
の間のリンクの長さ,
と
をそれぞれリンク上の圧縮力と張力とすると,上記のモデルは下の線形最適化問題に変換することができる.
anchorPoints = Thread[{0, Range[-3, 3]}];forcingPoint = {30, 0};connectivityPattern = Partition[Flatten[{Thread[{{-1, 1}, 0}], Outer[List, Range[-3, 3], {-1, 1}], Outer[List, {-3, -1, 1, 3}, {-2, 2}], Outer[List, {-2, -1, 1, 2}, {-3, 3}]}], 2];bounds = {{0, 30}, {-10, 10}};
nodes = Flatten[Outer[List, Sequence@@Apply[Range, bounds, 1]], 1];
np = Length[nodes];mid = Round[Map[Mean, bounds]];
cmid = Map[Plus[mid, #]&, connectivityPattern];
Graphics[{Point[nodes], Blue, Map[Circle[#, .5]&, anchorPoints], Red, Arrow[{forcingPoint, forcingPoint - {0, 2}}], Map[Line[{mid, #}]&, cmid]}, ImageSize -> Medium]toIndex = AssociationThread[nodes -> Range[np]];
fromIndex = AssociationThread[Range[np] -> nodes];anchorPointIndex = Lookup[toIndex, anchorPoints];
forcePointIndex = toIndex[forcingPoint];connectivity[index_, pat_] := Module[{point = fromIndex[index], connectedPoints, connectedIndexes},
connectedPoints = Map[Plus[point, #]&, pat];
connectedIndexes = Cases[Map[toIndex, connectedPoints], Except[_Missing]];
Thread[{index, Sort[connectedIndexes]}]];nodePosition = Join@@Map[connectivity[#, connectivityPattern]&, Range[np]];
nodeConnectivityMatrix = SparseArray[nodePosition -> 1, {np, np}]links = DeleteDuplicates[Map[Sort, nodeConnectivityMatrix["NonzeroPositions"]]];
nlinks = Length[links];linkToIndex = AssociationThread[links -> Range[nlinks]];links = DeleteDuplicates[Map[Sort, nodeConnectivityMatrix["NonzeroPositions"]]];
nlinks = Length[links];
linkLengths = Map[EuclideanDistance@@nodes[[#]]&, links];objective = linkLengths.(xp + xm);nodeForce = ConstantArray[0., {np, 2}];nodeForce[[forcePointIndex]] = {0., -1.};columns = nodeConnectivityMatrix["MatrixColumns"];
linkToIndex = AssociationThread[links -> Range[nlinks]];
linkConstraints = Table[
mi = columns[[i]];
vii = Map[Sort, Thread[{i, mi}]];
vi = Map[Indexed[xp, linkToIndex[#]] - Indexed[xm, linkToIndex[#]]&, vii];
s = Map[(nodes[[#]] - nodes[[i]])&, mi];
lhs = Total[Map[# / Norm[#]&, s] * vi];
Thread[lhs == nodeForce[[i]]]
, {i, Complement[Range[np], anchorPointIndex]}];constraints = Join[Flatten[linkConstraints], {xp0, xm0}];res = LinearOptimization[objective, constraints, {xp∈Vectors[nlinks],
xm∈Vectors[nlinks]}];totalf = (xp - xm) /. res;
maxForce = Max[Abs[totalf]];
index = Pick[Range[nlinks], Thread[Abs[totalf] / maxForce ≥ 0.001], True];
allLinks = Table[
f = totalf[[i]] / maxForce;
vlink = nodes[[links[[i]]]];
{Hue[(1 + f) / 2.5], Thickness[.025 Abs[f]], Line[vlink]},
{i, index}];
Graphics[{allLinks, {PointSize[0.02], Point[anchorPoints]}, {EdgeForm[StandardGray], FaceForm[None], Rectangle[{-1, -10}, {0.01, 10}]}}, ImageSize -> Medium]線形最適化のアルゴリズム
シンプレックス法と改訂シンプレックス法
シンプレックス法と改訂シンプレックス法は,制約条件により定義された多面体の頂点で実行可能解を構築し,その後目的関数のより小さな値を連続的に使い,最小値に達するまでその多面体の辺を頂点に向かって移動させていくことにより最適化問題を解く.
シンプレックス法と改訂シンプレックス法の実装が少ないと実際に非常に効率的であり,大域的最適値が見付かることが保障されているが,最悪の場合には動作に問題が生じる場合もある.構築された線形最適化問題に対して,シンプレックス法と改訂シンプレックス法がその問題の大きさに指数関数的な数のステップを取らなければならなくなる可能性があるのである.
Wolfram言語は密な線形代数を使ってシンプレックス法と改訂シンプレックス法を実装する.この実装のユニークな点は,厳密・拡張精度問題が解けるという点である.従って,これらのメソッドは機械数でない結果が必要とされる小さい問題により適している.
SeedRandom[123];
{m, n} = {20, 100};
c = RandomInteger[{1, 10}, n];
A = RandomInteger[{-100, 100}, {m, n}];
b = A.ConstantArray[1, n];
constraints = {A.xb, -10x10};t = Timing[res = LinearOptimization[c.x, constraints, x,
"PrimalMinimizerVector", Method -> "Simplex"];]; Print["time = ", t[[1]], " optimal value = ", c.res, " or ", N[c.res]]t = Timing[res = LinearOptimization[c.x, constraints, x,
"PrimalMinimizerVector", Method -> "RevisedSimplex"];]; Print["time = ", t[[1]], " optimal value = ", c.res, " or ", N[c.res]]t = Timing[res = LinearOptimization[c.x, constraints, x,
"PrimalMinimizerVector", Method -> "InteriorPoint"];];
Print["time = ", t[[1]], " optimal value = ", c.res]内点法
シンプレックス法と改訂シンプレックス法は通常非常に効率的であるが,最悪の動作をする場合もある.シンプレックス法と改訂シンプレックス法が問題の大きさに指数関数的な数のステップを取らなければならないような線形最適化問題を構築する可能性があるのである.
さらにWolfram言語ではシンプレックス法と改訂シンプレックス法の実装には密な線形代数が使われるが,内点法の実装には機械数の疎な線形代数が使われる.従って,機械数の大規模な線形最適化問題には,内点法の方が効率的なのでこれを使うべきである.
内点法の公式
ここで
,
,
である.この問題は,正の制約条件を扱う障壁関数式を使って解くことができる.
が成り立つ.これは制約条件を持つ
の線形/非線形方程式の集合である.これはニュートン法
で解くことができる.この線形系を解く方法のひとつに,ガウス消去法を使い行列をブロック三角行列形式に簡約するというものがある.
このブロック三角行列を解くためには,この行列が通常の系に含まれる,いわゆる通常の系を解く.
この行列は正定値行列になるが,解に近付くにつれ非常に悪条件になる.よって解法を安定させるために数値的手法が使われる.通常内点法は,「収束の許容誤差」で説明する許容範囲では,ほぼ
付近までの問題を解くよう想定されている.Wolfram言語ではMehrotraの予測子・修正子法[1]が使われている.
収束の許容誤差
参考文献
関連するテクニカルノート
-
▪
- 制約条件付き最適化 ▪
- 局所的非線形数値最適化 ▪
- 大域的非線形数値最適化 ▪
- 厳密な大域的最適化

