JavaScriptを有効にしてください

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

 ·   5 min read

※記事内に商品プロモーションを含むことがあります。

はじめに

最適化フレームワーク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としました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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]

ソースコードの解説

以下、ソースコードを簡単に解説します。

変数・パラメータの定義

1
2
3
4
5
6
7
8
9
# 変数・パラメータの定義
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クラスで設定します。

制約式の定義

1
2
3
# 制約式の定義
opti.subject_to(A@x <= b)
opti.subject_to(x >= 0)

制約式はopti.subject_to()で定義します。

行列とベクトルの積、または行列同士の積は@記号で定義します。*記号を使った場合、要素同士の積になります。

また、opti.subject_to()内の式がベクトルになる場合、各要素に対して制約式が定義されます。

評価関数の定義

1
2
3
# 評価関数の定義
obj = c.T@x
opti.minimize(-obj)

最小化する評価関数をopti.minimize()で定義します。最大化 (maximize()) は実装されていないため、評価関数に-を掛けて最小化します。

なお、c.T@xでは内積を計算しています。この式はca.sum1(c*x)(要素同士の積をとり、和を取る)と等価です。

参考

CasADiの公式リファレンス
CasADi - Docs

シェアする

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

サイト内検索