gurobipy エラー
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