メインコンテンツへスキップ

CasADiで最適化の変数と制約をベクトル化する

·1082 文字·3 分
目次

はじめに
#

最適化フレームワーク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の公式リファレンス

CasADi - Docs

Helve
著者
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

関連記事

CasADiとIPOPTで非線形計画問題を解く
··2122 文字·5 分
Pythonで自動微分・非線形最適化ライブラリCasADiと最適化ソルバIPOPTを使って、制約付き非線形計画問題を解く方法をまとめた。
CasADiとBONMINで混合整数非線形計画問題を解く
·913 文字·2 分
Pythonで自動微分・非線形最適化ライブラリCasADiと最適化ソルバBONMINを使って、混合整数非線形計画問題を解く方法をまとめた。
PythonとCasADiを使ったDirect Multiple Shooting法による最適制御
·2473 文字·5 分
Pythonと最適化ライブラリCasADiを使って、Direct Multiple Shooting法と呼ばれる手法によって最適制御問題を解きました。
最適制御向け最適化ライブラリOpEnのRust build of TCP interface failedエラーについて
·1185 文字·3 分
OpEnで発生するRust build of TCP interface failedエラーの解消方法を示します。
PythonとCasADiを使ったDirect Single Shooting法による最適制御
·2545 文字·6 分
Pythonと最適化ライブラリCasADiを使って、Direct Single Shooting法と呼ばれる手法によって最適制御問題を解きました。対象とした例題は斜方投射(物体を斜め方向に上げる)で、指定の時刻・距離に物体を到達させる最小の初速度を求めます。
最適制御向け最適化ライブラリOpEnに入門する
··1759 文字·4 分
Rust製の最適制御向け最適化ライブラリOpEnに入門するためチュートリアルの非線形計画問題を解いたので、備忘録を兼ねてまとめた。