Python 纸浆调度程序需要更有效的问题定义
我用纸浆写了一个程序来优化我的联赛时间表。 共有16名球员和7个回合。 每轮由4场比赛组成。每场比赛是两人对两人。 每个玩家都有一个等级。 目标是最小化团队之间的绝对评分差异。 约束条件是每个玩家:Python 纸浆调度程序需要更有效的问题定义,python,linear-programming,pulp,Python,Linear Programming,Pulp,我用纸浆写了一个程序来优化我的联赛时间表。 共有16名球员和7个回合。 每轮由4场比赛组成。每场比赛是两人对两人。 每个玩家都有一个等级。 目标是最小化团队之间的绝对评分差异。 约束条件是每个玩家: 必须打7轮 每轮只能玩1局 只能与其他玩家合作0或1次 只能成为其他玩家的对手0、1或2次 下面的代码可以工作,但需要几分钟才能运行。我是一名经验丰富的python程序员,但在线性编程方面相对来说是新手,因此我不确定是否可以更有效地定义问题以加快解决时间 import pulp import n
- 必须打7轮
- 每轮只能玩1局
- 只能与其他玩家合作0或1次
- 只能成为其他玩家的对手0、1或2次
import pulp
import numpy as np
p = np.array(['Joe', 'Tom', 'Sam', 'Bill', 'Fred', 'John', 'Wex', 'Chip',
'Mike', 'Jeff', 'Steve', 'Kumar', 'Connor', 'Matt', 'Peter', 'Cindy'])
r = np.array([5.0, 4.2, 4.3, 5.1, 4.4, 3.7, 3.8, 4.6, 3.2, 3.6, 3.8, 4.7, 4.3, 4.6, 4.2, 3.4])
s = dict(zip(p, r))
n_games = 7
# calculate team combinations
team_combos = list(pulp.combination(p, 2))
# calculate game combinations
# each item is a 3-tuple of tuple(team1), tuple(team2), game_number
game_combos = []
for t in team_combos:
for tt in team_combos:
if t[0] in tt or t[1] in tt:
continue
for game_number in np.arange(n_games) + 1:
game_combos.append((t, tt, game_number))
# calculate game score differential
game_scores = {}
for gc in game_combos:
p1, p2 = gc[0]
p3, p4 = gc[1]
game_scores[(gc[0], gc[1])] = np.abs((s[p1] + s[p2]) - (s[p3] + s[p4]))
# decision variables
gcvars = pulp.LpVariable.dicts('gc_decvar', game_combos, cat=pulp.LpBinary)
# create problem
# minimize game scores subject to constraints
prob = pulp.LpProblem("PBOpt", pulp.LpMinimize)
# objective function
# minimize difference between team scores
prob += pulp.lpSum([gcvars[gc] * game_scores[(gc[0], gc[1])] for gc in game_combos])
# constraints
# each player must have n_games games
for player in p:
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] or player in k[1])]) == n_games
# each player has 1 game per game_number
for player in p:
for game_number in np.arange(1, n_games + 1):
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] or player in k[1]) and
k[2] == game_number]) == 1
# do not play with a player more than once
# do not play against a player more than twice
for player in p:
for pplayer in p:
if player == pplayer:
continue
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] and pplayer in k[0]) or
(player in k[1] and pplayer in k[1])]) <= 1
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] and pplayer in k[1]) or
(player in k[1] and pplayer in k[0])]) <= 2
# solve and print solution
prob.solve()
print([k for k, v in gcvars.items() if v.varValue == 1])
进口纸浆
将numpy作为np导入
p=np.数组(['Joe','Tom','Sam','Bill','Fred','John','Wex','Chip',
“迈克”、“杰夫”、“史蒂夫”、“库马尔”、“康纳”、“马特”、“彼得”、“辛迪”])
r=np.数组([5.0,4.2,4.3,5.1,4.4,3.7,3.8,4.6,3.2,3.6,3.8,4.7,4.3,4.6,4.2,3.4])
s=dict(zip(p,r))
n_games=7
#计算团队组合
团队组合=列表(纸浆组合(p,2))
#计算游戏组合
#每个项目都是一个三元组,包括元组(team1)、元组(team2)、游戏编号
游戏组合=[]
对于团队_组合中的t:
对于团队组合中的tt:
如果tt中的t[0]或tt中的t[1]:
持续
对于np.arange(n_对策)+1中的对策编号:
游戏组合。追加((t,tt,游戏编号))
#计算比赛分数差
比赛分数={}
对于游戏组合中的gc:
p1,p2=gc[0]
p3,p4=gc[1]
游戏分数[(gc[0],gc[1])]=np.abs((s[p1]+s[p2])-(s[p3]+s[p4]))
#决策变量
gcvars=pilp.LpVariable.dicts('gc_decvar',game_combos,cat=pilp.LpBinary)
#制造问题
#根据限制最小化游戏分数
prob=纸浆.LpProblem(“PBOpt”,纸浆.LpProblem)
#目标函数
#尽量减少团队得分之间的差异
prob+=palp.lpSum([gcvars[gc]*游戏组合中gc的游戏分数[(gc[0],gc[1]))
#约束条件
#每个玩家必须有n_游戏
对于p中的玩家:
prob+=纸浆lpSum([v代表k,v代表gcvars.items()
if(k[0]中的玩家或k[1]中的玩家)==n_游戏
#每个玩家每个游戏编号有1个游戏
对于p中的玩家:
对于np.arange(1,n_games+1)中的game_数:
prob+=纸浆lpSum([v代表k,v代表gcvars.items()
if(k[0]中的玩家或k[1]中的玩家)和
k[2]==游戏编号]==1
#不要与玩家玩超过一次
#与一名球员的比赛不要超过两次
对于p中的玩家:
对于PPP中的图层:
如果player==pplayer:
持续
prob+=纸浆lpSum([v代表k,v代表gcvars.items()
if(k[0]中的玩家和k[0]中的pplayer)或
(k[1]中的玩家和k[1]中的pplayer])好消息/坏消息
骨头上还有一点肉可以修剪。有几个循环正在生成冗余元素。坏消息是,解算器通常可以检测到这些,并将它们剔除,因此通过修剪它们,您可能不会获得太大的加速度
三件事
你对玩家必须有n个游戏的限制是多余的,因为你的下一个限制迫使他们在每一轮都有一个游戏
当您创建player
-pplayer
约束时,您创建了许多重复项,因为您隐式地排序p
和pp
。如果集合P有16个玩家,那么嵌套循环将在忽略P=pp时创建每种类型的P*(P-1)约束。但是,请注意,只有C(16,2)逻辑约束是P*(P-1)/2
在创建法律游戏集时,您也在做类似的事情,因为您隐式地为法律团队排序
下面是您的程序经过调整的版本。。。。我的机器还在运转,所以我不知道是否能节省时间。您的其他“简单”选项是修补优化差距或超时
我会在这上面再炖一点。。。但我不确定是否有另一种新颖的方法
import pulp
import numpy as np
p = np.array(['Joe', 'Tom', 'Sam', 'Bill', 'Fred', 'John', 'Wex', 'Chip',
'Mike', 'Jeff', 'Steve', 'Kumar', 'Connor', 'Matt', 'Peter', 'Cindy'])
r = np.array([5.0, 4.2, 4.3, 5.1, 4.4, 3.7, 3.8, 4.6, 3.2, 3.6, 3.8, 4.7, 4.3, 4.6, 4.2, 3.4])
s = dict(zip(p, r))
n_games = 7
# calculate team combinations
team_combos = list(pulp.combination(p, 2))
# calculate game combinations
# each item is a 3-tuple of tuple(team1), tuple(team2), game_number
legal_games = [(t[0], t[1]) for t in pulp.combination(team_combos, 2) if not set(t[0])&set(t[1])]
game_combos = []
for t, tt in legal_games:
for game_number in np.arange(n_games) + 1:
game_combos.append((t, tt, game_number))
# calculate game score differential
game_scores = {}
for gc in game_combos:
p1, p2 = gc[0]
p3, p4 = gc[1]
game_scores[(gc[0], gc[1])] = np.abs((s[p1] + s[p2]) - (s[p3] + s[p4]))
# decision variables
gcvars = pulp.LpVariable.dicts('gc_decvar', game_combos, cat=pulp.LpBinary)
# create problem
# minimize game scores subject to constraints
prob = pulp.LpProblem("PBOpt", pulp.LpMinimize)
# objective function
# minimize difference between team scores
prob += pulp.lpSum([gcvars[gc] * game_scores[(gc[0], gc[1])] for gc in game_combos])
# constraints
# each player must have n_games games
# for player in p:
# prob += pulp.lpSum([v for k, v in gcvars.items()
# if (player in k[0] or player in k[1])]) == n_games
# each player has 1 game per game_number
for player in p:
for game_number in np.arange(1, n_games + 1):
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] or player in k[1]) and
k[2] == game_number]) == 1
# do not play with a player more than once
# do not play against a player more than twice
for player, pplayer in team_combos:
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] and pplayer in k[0]) or
(player in k[1] and pplayer in k[1])]) <= 1
prob += pulp.lpSum([v for k, v in gcvars.items()
if (player in k[0] and pplayer in k[1]) or
(player in k[1] and pplayer in k[0])]) <= 2
# solve and print solution
prob.solve()
print([k for k, v in gcvars.items() if v.varValue == 1])
进口纸浆
将numpy作为np导入
p=np.数组(['Joe','Tom','Sam','Bill','Fred','John','Wex','Chip',
“迈克”、“杰夫”、“史蒂夫”、“库马尔”、“康纳”、“马特”、“彼得”、“辛迪”])
r=np.数组([5.0,4.2,4.3,5.1,4.4,3.7,3.8,4.6,3.2,3.6,3.8,4.7,4.3,4.6,4.2,3.4])
s=dict(zip(p,r))
n_games=7
#计算团队组合
团队组合=列表(纸浆组合(p,2))
#计算游戏组合
#每个项目都是一个三元组,包括元组(team1)、元组(team2)、游戏编号
合法博弈=[(t[0],t[1])对于纸浆中的t。组合(团队组合,2)如果未设置(t[0])和设置(t[1])]
游戏组合=[]
对于法律游戏中的t、tt:
对于np.arange(n_对策)+1中的对策编号:
游戏组合。追加((t,tt,游戏编号))
#计算比赛分数差
比赛分数={}
对于游戏组合中的gc:
p1,p2=gc[0]
p3,p4=gc[1]
游戏分数[(gc[0],gc[1])]=np.abs((s[p1]+s[p2])-(s[p3]+s[p4]))
#决策变量
gcvars=pilp.LpVariable.dicts('gc_decvar',game_combos,cat=pilp.LpBinary)
#制造问题
#根据限制最小化游戏分数
prob=纸浆.LpProblem(“PBOpt”,纸浆.LpProblem)
#目标函数
#尽量减少团队得分之间的差异
prob+=palp.lpSum([gcvars[gc]*游戏组合中gc的游戏分数[(gc[0],gc[1]))
#约束条件
#每个玩家必须有n_游戏
#对于p中的玩家:
#prob+=纸浆lpSum([v代表k,v代表gcvars.items()
#if(k[0]中的玩家或k[1]中的玩家)==n_游戏
#每个玩家每个游戏编号有1个游戏
对于p中的玩家:
对于np.arange(1,n_games+1)中的game_数:
prob+=纸浆lpSum([v代表k,v代表gcvars.items()
如果(k[0]中的玩家或k[1]中的玩家)是