Gurobi+C++
やりたいこと
をGurobiに解かせる。 ホスト言語はC++14。 なお、ここでは
であることに注意。
やり方
まずはgurobi_c++.h
と、(例のために)vector
、random
をインクルード。
#include <gurobi_c++.h> #include <vector> #include <random> // インタンスを乱数で用意するため
そしてGRBEnv
とGRBModel
を用意。
auto env = new GRBEnv{}; auto model = new GRBModel{*env};
そして変数追加。
auto x = std::vector<GRBVar>{}; for (auto i = 0; i < 10; i++) { x.push_back( model->addVar( 0, // 下限 GRB_INFINITY, // 上限 1, // 初期値 GRB_CONTINUOUS // 変数のタイプ ) ); }
タイプには表のものを指定できる。
範囲 | 使用する定数 |
---|---|
連続 | GRB_CONTINUOUS |
バイナリ | GRB_BINARY |
整数 | GRB_INTEGER |
終わったらモデルを更新。
model->update();
必要な制約を追加していく。
auto seed_gen1 = std::random_device{}; auto mt1 = std::mt19937{seed_gen1()}; auto a_dist = std::uniform_real_distribution<>{-10000, 10000}; auto b_dist = std::uniform_real_distribution<>{-1000, 1000}; auto d_dist = std::uniform_real_distribution<>{100, 10000}; for (auto i = 0; i < 5; i++) { GRBQuadExpr constr = 0.0; for (auto& ex : x) { constr += a_dist(mt1) * ex; } model->addConstr(constr == b_dist(mt1)); // 線形制約追加 } GRBQuadExpr constr = 0.0; for (auto& ex: x) { constr += ex * ex; } model->addConstr(constr >= d_dist(mt1));
制約を追加したらモデルを更新。
model->update();
最後に目的関数を作成してセット。
GRBQuadExpr objective = 0.0; auto seed_gen2 = std::random_device{}; auto mt2 = std::mt19937{seed_gen2}; auto c_dist = std::unifrom_real_distribution<>{-1000, 1000}; for (auto* ex : x) { objective += c_dist(mt2) * ex; } model->setObjective(objective, GRB_MINIMIZE)
ここでは最小化問題を扱っているので、GRB_MINIMIZEを指定しているが、最大化したければ、
GRB_MAXIMIZE`を指定する。
最後に更新。
model->update();
そして最後に解く。
model->optimize();
解いた後に
解いたあとに最適解が得られているのかどうなのかは
model->get(GRB_IntAttr_Status);
の返り値でわかる。最適解が出ていればGRB_OPTIMAL
が返る。
目的関数値が欲しけば、
model->get(GRB_DoubleAttr_ObjVal);
とすればよい。
最後にアロケートしたメモリを解放。
delete mode; delete env;
model
->env
の順番でなければ例外が飛ぶ。
コンパイル
GUROBI_HOME
を設定しておいていることを仮定している。
Mac+Gurobi 8.0.1なら/Library/gurobi801/mac64
。
もし、設定していないなら(bash
系列であれば)
$ export GUROBI_HOME=/Library/gurobi801/mac64
とかしておくこと。
コンパイル自体は次のコマンドでできる(ファイル名はmain.cc
にしている)。
$ clang -std=c++14 -Wall -pedantic -L"$GUROBI_HOME/lib" -I"$GUROBI_HOME/include" -lgurobi80 -lgurobi_c++ main.cc
Tips
- 例外は
GRBException
をキャッチすればよい(try { ... } catch (GREBException ex) { 例外処理 }
)。- エラーのステータスコードは
ex.getErrorCode()
で見れる。ステータスコードの詳細はオンラインドキュメントを参照。(バージョンが古いとURL変わってて見れないかも。その場合はURLのバージョニングの部分を弄る) ex.getMessage()
でエラー文を見れる。
- エラーのステータスコードは