複数の最適解をGurobiで求めたい

整数変数の値が異なる解を列挙するには,

  • PoolSearchModeを2に設定する.

  • 列挙する解の個数を制限する.

  • PoolGapを0にする.

として問題を解けばよい.

from gurobipy import *

model = Model("count the number of optimal solutions")

model.setParam("PoolSearchMode", 2)
model.setParam("PoolSolutions", 200)
model.setParam("PoolGap", 0)
model.setParam("SolFiles","./test")

I = [1,2,3]
x = {}
for i in I:
	x[i] = model.addVar(vtype="B", name=f"x({i})")

model.setObjective(quicksum(x[i] for i in I), GRB.MINIMIZE)
model.addConstr(quicksum(x[i] for i in I)==1, name="equal")

model.optimize()

PoolSearchModeが2の場合,目的関数を設定しても無視するようである.実行すると,test_0.sol, test_1.sol, test_2.solの3つのファイルを生成する.この場合,解の個数は3個である.それらの中身は,次のようになっている.

# Solution for model count the number of optimal solutions
# Objective value = 1
x(1) 1
x(2) 0
x(3) 0
# Solution for model count the number of optimal solutions
# Objective value = 1
x(1) 0
x(2) 1
x(3) 0
# Solution for model count the number of optimal solutions
# Objective value = 1
x(1) 0
x(2) 0
x(3) 1

もし目的関数の最適値PI*がわかっており,最適解を複数個列挙する場合は,

PI<= PI*

を制約式にすればよい.次の例では,x[1]<=0を制約として追加した.

from gurobipy import *

model = Model("count the number of optimal solutions")

model.setParam("PoolSearchMode", 2)
model.setParam("PoolSolutions", 200)
model.setParam("PoolGap", 0)
model.setParam("SolFiles","./test")

I = [1,2,3,4]
x = {}
for i in I:
	x[i] = model.addVar(vtype="B", name=f"x({i})")

model.addConstr(quicksum(x[i] for i in I)==1, name="equal")
model.addConstr(x[1]<=0)

model.optimize()

結果は以下のようになり,x(1)=0のもとで,3つの解を列挙できている.

x(1) 0
x(2) 0
x(3) 0
x(4) 1
x(1) 0
x(2) 1
x(3) 0
x(4) 0
x(1) 0
x(2) 0
x(3) 1
x(4) 0

あるいは,SolCountとSolutionNumberを使って次のようにしてもよい.

from gurobipy import *

# モデルを作成
model = Model("count the number of optimal solutions")

# 変数を定義
I = [1,2,3,4]
x = {}
for i in I:
	x[i] = model.addVar(vtype="B", name=f"x({i})")

# 制約条件を追加
model.addConstr(quicksum(x[i] for i in I)==1, name="equal")
model.addConstr(x[1]<=0)

# PoolSearchModeを2にPoolGapを0に設定
model.Params.PoolSearchMode = 2
model.Params.PoolGap = 0

# 最適化を実行
model.optimize()

# 解の列挙
if model.SolCount > 0:
    print("最適解を含むプール内の解:")
    for i in range(model.SolCount):
        model.Params.SolutionNumber = i
        print(f"Solution {i + 1}:")
        for var in model.getVars():
            print(f"{var.VarName}: {var.Xn}")
else:
    print("解が見つかりませんでした。")

出力結果は,次のようになる.

最適解を含むプール内の解:
Solution 1:
x(1): 0.0
x(2): 0.0
x(3): 0.0
x(4): 1.0
Solution 2:
x(1): 0.0
x(2): 1.0
x(3): -0.0
x(4): -0.0
Solution 3:
x(1): 0.0
x(2): -0.0
x(3): 1.0
x(4): -0.0

いいなと思ったら応援しよう!