はじめに #
最適化フレームワークCasADiのOptiスタックで、多変数の最適化を簡潔に記述するため、変数と制約をベクトル化する方法をまとめました。言語はPythonです。
検証環境は以下の通りです。
ソフトウェア | バージョン |
---|---|
Python | 3.9.7 |
CasADi | 3.6.3 |
対象とする最適化問題 #
以下の2変数最適化問題を考えます。
$$ \begin{array}{ll} \text{maximize} \ & x_1 + 2x_2 \\\ \text{subject to} \ & 3x_1 + x_2 \le 9 \\\ & x_1 + 3x_2 \le 6 \\\ & x_1 \ge 0, \ x_2 \ge 0 \end{array}$$ここで、
$$A=\left[ \begin{array}{cc} 3 & 1 \\\ 1 & 3 \end{array} \right], \ b=\left[ \begin{array}{c} 9 \\\ 6 \end{array} \right], \ c=\left[ \begin{array}{c} 1 \\\ 2 \end{array} \right]$$とおいて、最適化問題を次式の一般的な線形計画問題の形式とします。
$$ \begin{array}{ll} \text{maximize} \ & c^{\top}x \\\ \text{subject to} \ & Ax \le b \\\ & x \ge 0 \end{array} $$この形式に従ってコーディングします。
CasADiのソースコード #
上記の最適化問題をPython+CasADiで記述します。最適化ソルバはIPOPTとしました。
import casadi as ca
opti = ca.Opti()
# 変数・パラメータの定義
x = opti.variable(2)
A = opti.parameter(2, 2)
b = opti.parameter(2)
c = opti.parameter(2)
opti.set_value(A, ca.DM([[3, 1], [1, 3]]))
opti.set_value(b, [9, 6])
opti.set_value(c, [1, 2])
# 制約式の定義
opti.subject_to(A@x <= b)
opti.subject_to(x >= 0)
# 評価関数の定義
obj = c.T@x
opti.minimize(-obj)
# ソルバの定義
opti.solver('ipopt')
# 最適化計算の実行・結果の表示
sol = opti.solve()
print(f"評価関数: {sol.value(obj)}")
print(f"x: {sol.value(x)}")
実行すると、(IPOPTのログの後に)最適化結果が以下の通り表示されます。
評価関数: 4.875000043735819
x: [2.62500002 1.12500001]
ソースコードの解説 #
以下、ソースコードを簡単に解説します。
変数・パラメータの定義 #
# 変数・パラメータの定義
x = opti.variable(2)
A = opti.parameter(2, 2)
b = opti.parameter(2)
c = opti.parameter(2)
opti.set_value(A, ca.DM([[3, 1], [1, 3]]))
opti.set_value(b, [9, 6])
opti.set_value(c, [1, 2])
最適化の変数はopti.variable()
, 固定値となるパラメータはopti.parameter()
でそれぞれ定義します。(2)
は2次元のベクトル、(2, 2)
は2×2行列となります。
また、パラメータにはopti.set_value()
で値を設定します。ベクトルの場合はリストで設定できますが、行列の場合はDM
クラスで設定します。
制約式の定義 #
# 制約式の定義
opti.subject_to(A@x <= b)
opti.subject_to(x >= 0)
制約式はopti.subject_to()
で定義します。
行列とベクトルの積、または行列同士の積は@
記号で定義します。*
記号を使った場合、要素同士の積になります。
また、opti.subject_to()
内の式がベクトルになる場合、各要素に対して制約式が定義されます。
評価関数の定義 #
# 評価関数の定義
obj = c.T@x
opti.minimize(-obj)
最小化する評価関数をopti.minimize()
で定義します。最大化 (maximize()
) は実装されていないため、評価関数に-
を掛けて最小化します。
なお、c.T@x
では内積を計算しています。この式はca.sum1(c*x)
(要素同士の積をとり、和を取る)と等価です。
参考 #
CasADiの公式リファレンス