学習理論の学習

統計的学習理論を学習してるときに思ったこととか

Gurobiの使い方(python3)

最適化ソルバの一つである Gurobi の使い方について.

はじめに

これは私が頻繁に最適化ソルバを使うので,方法を忘れないための記事です. 多少わかりにくいところ,もしくは使い方を間違っているところがあればぜひ教えてください.

注意書き

本記事を書いた時点で,私のダウンロードしている Gurobi のバージョンは 9.0.1. なので, この記事を参考にしてプログラムを書こうという方は適宜自分のバージョンに置き換えて読んでください. また,jupyter notebookで実行しようとしてmodule import errorが出るときは,次のコマンドを打てば解決すると思います.

$ conda config --add channels http://conda.anaconda.org/gurobi
$ conda install gurobi

解きたい問題

前に書いたGurobiの使い方(C++) で解いた問題と同じ問題を解いてみようと思います. ocelot.hatenadiary.com 次式で定義される行列 A \in \mathbb{R}^{2 \times 2},ベクトル  b \in \mathbb{R}^{2}


A =
\begin{pmatrix}
-1 & 2 \\
0 & 1 \\
\end{pmatrix}, \quad
b =
\begin{pmatrix}
0 \\
6
\end{pmatrix}

を用いて,次のような最適化問題を考えます.


\min
\left\{
(x _ 1- 3)^2 + (x _ 2 - 4)^2 \mid A x \leq b, x _ 1 \geq 0, x _ 2 \geq 0
\right\}

この問題の最適値は 5で, 最適解は


x =
\begin{pmatrix}
x _ 1 \\
x _ 2
\end{pmatrix}
=
\begin{pmatrix}
4 \\ 2
\end{pmatrix}

です. これらを求めるプログラムを書いてみようと思います.

プログラム

例えば,次のように書けます.

# -*- coding: utf-8 -*-
import gurobipy as gp
from gurobipy import GRB

# モデルの宣言
model = gp.Model(name="Test")

# 変数の宣言,初期化,モデルに追加.
x1 = model.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name='x')
x2 = model.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name='y')

# 制約をモデルに追加
constraint_1 = model.addConstr(-x1 + 2*x2 <= 0, name="constraint_1")
constraint_2 = model.addConstr(x1 <= 6, name="constraint_2")

# 目的関数の設定
objective = (x1 - 3)*(x1 - 3) + (x2 - 4)*(x2 - 4)
model.setObjective(objective, GRB.MINIMIZE)

# コンソールへの出力をなくす.
model.params.LogToConsole = False

# ソルバに解いてもらう.
model.optimize()

# 最適値の出力
print("Optimal Value: ".format(objective.getValue()))

# 最適解の出力
print("Optimal Solutions")
print("\t{} = {}".format(x1.varName, x1.x))
print("\t{} = {}".format(x2.varName, x2.x))

解きたい問題が最大化問題である場合,model.setObjective( objective, GRB.MAXIMIZE ) と書きます.

実行

普通のpythonのプログラムと同様に実行できます.

$ python main.py
Academic license - for non-commercial use only
Optimal Value: 
Optimal Solutions
    x = 4.000000000023386
    y = 1.9999999999694231

双対変数について

解いた問題の双対問題の解が欲しい場合,つぎのように書くと得られます.

for constr in model.getConstrs():
    print("The dual value of {} is {}.".format(constr.constrName, constr.pi))

終わりに

なんでC++で解いた時の出力とpython3で解いた時の出力に違いがあるのかな,出力の形式の違いなのかな,というのが地味に気になっています.