gurobipy とは GUROBI optimizerが提供するpythonインターフェイスです. pip で installできます.
gurobipyをクラス内で用いるときの注意点;
下記のプログラムは2変数(x, y)からなる簡単な最適化問題を求解するもの.
solve()関数で問題の定式化と求解を行なっています.
self.xとself.yにgurobipyの変数オブジェクト(gurobipy.Var)を格納しています;
import gurobipy class Problem: def __init__(self): self.x = None self.y = None def solve(self): model = gurobipy.Model() self.x = model.addVar(name = "x") self.y = model.addVar(name = "y") model.addConstr(-3*self.x + self.y <= 6) model.addConstr(-self.x - 2*self.y >= -4) model.setObjective(-self.x + 4*self.y) model.optimize() print(f"solve::obj:{model.ObjVal}") print(f"solve::x:{self.x.X}") print(f"solve::y:{self.y.X}") def print_solution(self): print(f"print_solution::x:{self.x.X}") print(f"print_solution::y:{self.y.X}") if __name__ == "__main__": problem = Problem() problem.solve() problem.print_solution()
これを実行すると, 下記のエラーが発生します.
Set parameter GURO_PAR_SPECIAL Set parameter TokenServer to value "hogehoge" Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64) Thread count: 48 physical cores, 96 logical processors, using up to 32 threads Optimize a model with 2 rows, 2 columns and 4 nonzeros Model fingerprint: 0x14dc6dc8 Coefficient statistics: Matrix range [1e+00, 3e+00] Objective range [1e+00, 4e+00] Bounds range [0e+00, 0e+00] RHS range [4e+00, 6e+00] Presolve removed 2 rows and 2 columns Presolve time: 0.00s Presolve: All rows and columns removed Iteration Objective Primal Inf. Dual Inf. Time 0 -4.0000000e+00 0.000000e+00 0.000000e+00 0s Solved in 0 iterations and 0.00 seconds (0.00 work units) Optimal objective -4.000000000e+00 solve::obj:-4.0 solve::x:4.0 solve::y:0.0 Traceback (most recent call last): File "/home/hogehoge/test.py", line 33, in <module> problem.print_solution() File "/home/hogehoge/test.py", line 26, in print_solution print(f"print_solution::x:{self.x.X}") File "src/gurobipy/var.pxi", line 125, in gurobipy.Var.__getattr__ File "src/gurobipy/var.pxi", line 153, in gurobipy.Var.getAttr File "src/gurobipy/attrutil.pxi", line 35, in gurobipy.__getattr File "src/gurobipy/attrutil.pxi", line 23, in gurobipy.__getattrinfo AttributeError: 'gurobipy.Var' object has no attribute 'X'
solve()関数内でのself.x.Xがきちんと表示されているのに, print_solution()関数ではself.xのX属性がなくなっています.
gurobipyの中身のコードをチェックしたいのですが, バイナリでパッケージが配られているので, 詳しいことは分かりませんが,
(おそらく)solve()関数スコープを抜ける際にmodelオブジェクトのメモリが解放されて, 求解情報がクリアされている模様.
これを防ぐにはmodelオブジェクトのメモリ解放を防げばいいので, 例えばクラス内属性として保存しておけば良いです. このような、スコープから外れて変数のメモリが解放されることを防ぐために、より大きなスコープに変数を紐づけておくことを( hook ) と言ったりします。フックに変数を引っ掛けるようなイメージなんですかね。
import gurobipy class Problem: def __init__(self): + self.model = None self.x = None self.y = None def solve(self): model = gurobipy.Model() self.x = model.addVar(name = "x") self.y = model.addVar(name = "y") model.addConstr(-3*self.x + self.y <= 6) model.addConstr(-self.x - 2*self.y >= -4) model.setObjective(-self.x + 4*self.y) model.optimize() + self.model = model print(f"solve::obj:{model.ObjVal}") print(f"solve::x:{self.x.X}") print(f"solve::y:{self.y.X}") def print_solution(self): print(f"print_solution::x:{self.x.X}") print(f"print_solution::y:{self.y.X}") if __name__ == "__main__": problem = Problem() problem.solve() problem.print_solution()
これで実行してみると、
Set parameter GURO_PAR_SPECIAL Set parameter TokenServer to value "hogehoge" Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (linux64) Thread count: 48 physical cores, 96 logical processors, using up to 32 threads Optimize a model with 2 rows, 2 columns and 4 nonzeros Model fingerprint: 0x14dc6dc8 Coefficient statistics: Matrix range [1e+00, 3e+00] Objective range [1e+00, 4e+00] Bounds range [0e+00, 0e+00] RHS range [4e+00, 6e+00] Presolve removed 2 rows and 2 columns Presolve time: 0.00s Presolve: All rows and columns removed Iteration Objective Primal Inf. Dual Inf. Time 0 -4.0000000e+00 0.000000e+00 0.000000e+00 0s Solved in 0 iterations and 0.00 seconds (0.00 work units) Optimal objective -4.000000000e+00 solve::obj:-4.0 solve::x:4.0 solve::y:0.0 print_solution::x:4.0 print_solution::y:0.0
うまくいきました。
補足 - python: v3.9.10 - gurobipy: v9.5.1