373 lines
13 KiB
Python
373 lines
13 KiB
Python
import csv
|
|
import operator
|
|
import os
|
|
import random
|
|
import sys
|
|
import time
|
|
import timeit
|
|
import datetime
|
|
# import networkx as nx
|
|
|
|
from datetime import datetime
|
|
|
|
from dateutil.parser import parse
|
|
from math import sqrt, pow, sin, cos, atan2, pi
|
|
|
|
try:
|
|
import simplejson as json
|
|
except:
|
|
import json
|
|
|
|
# from gurobipy import *
|
|
import xpress as xp
|
|
from multiprocessing import Pool, cpu_count
|
|
|
|
# import config
|
|
def simulate_craw_and_calendar(thread, nSimulations):
|
|
logfile = f'draw_feasibility/log_{datetime.now().strftime("%Y%m%d_%H%M%S")}_{thread}'
|
|
|
|
getTeamsOfPot = { p: [ p+str(i) for i in range(1,10) ] for p in ["A","B","C","D"] }
|
|
|
|
allTeams = getTeamsOfPot['A']+getTeamsOfPot['B']+getTeamsOfPot['C']+getTeamsOfPot['D']
|
|
activeTeams= allTeams
|
|
pots = getTeamsOfPot.keys()
|
|
# print (pots)
|
|
|
|
gamesAgainst = { (p1,p2) : 2 for p1 in pots for p2 in pots}
|
|
|
|
# for p in pots:
|
|
# gamesAgainst[(p,p)]=2
|
|
|
|
# for (p1,p2) in [('A','D'), ('D','A'), ('B','C'), ('C','B') ]:
|
|
# gamesAgainst[(p1,p2)]=2
|
|
|
|
nMatchDays=8
|
|
|
|
|
|
# for p1 in pots:
|
|
# for p2 in pots:
|
|
# print (p1,p2,gamesAgainst[(p1,p2)])
|
|
# print()
|
|
|
|
# print (allTeams)
|
|
|
|
cntr=0
|
|
|
|
# mbus = Model("Draw")
|
|
mbus = xp.problem("Draw")
|
|
|
|
possAssigns= [ (t1,t2) for t1 in allTeams for t2 in allTeams if t1!=t2]
|
|
# print (possAssigns)
|
|
|
|
|
|
# plays = mbus.addVars(possAssigns, vtype=GRB.BINARY)
|
|
plays = {pa:xp.var(vartype=xp.binary) for pa in possAssigns}
|
|
mbus.addVariable(plays)
|
|
|
|
for (t1,t2) in possAssigns:
|
|
if t1<t2:
|
|
# mbus.addConstr( plays[(t1,t2)] ==plays[(t2,t1)] )
|
|
mbus.addConstraint( plays[(t1,t2)] ==plays[(t2,t1)] )
|
|
|
|
for p in pots:
|
|
for t in getTeamsOfPot[p]:
|
|
for p2 in pots:
|
|
# mbus.addConstr( quicksum(plays[(t,t2)] for t2 in getTeamsOfPot[p2] if t!=t2 ) == gamesAgainst[(p,p2)])
|
|
mbus.addConstraint( xp.Sum(plays[(t,t2)] for t2 in getTeamsOfPot[p2] if t!=t2 ) == gamesAgainst[(p,p2)])
|
|
|
|
|
|
# for (t1,t2) in [("A1","A2"), ("A2","A3"), ("A3","A1"),
|
|
# ("B1","B2"), ("B2","B3"), ("B3","B1"),
|
|
# ("C1","C2"), ("C2","C3"), ("C3","C1"),
|
|
# # ("D1","D2"), ("D2","D3"), ("D3","D1"),
|
|
# ] :
|
|
# mbus.addConstr( plays[(t1,t2)] == 1)
|
|
|
|
|
|
# for (p1,p2) in [ ("A","B"), ("B","C"), ("C","D"), ("D","A") ]:
|
|
# for (n1,n2) in [ (1,1),(1,2),(3,2),(3,3),(2,3) ,(2,1)]:
|
|
# mbus.addConstr( plays[( p1+str(n1) , p2+str(n2))] == 1)
|
|
|
|
|
|
# potpairs = [ (p1,p2) for p1 in pots for p2 in pots if p1!=p2]
|
|
# clusters = [[1,2,3], [4,5,6], [7,8,9]]
|
|
|
|
# for cl in clusters:
|
|
# for (p1,p2) in potpairs:
|
|
# if len(cl)==2:
|
|
# mbus.addConstr( quicksum(plays[( p1+str(n1),p2+str(n2))] for n1 in cl for n2 in cl ) == 4)
|
|
# print ( [( p1+str(n1),p2+str(n2)) for n1 in cl for n2 in cl ])
|
|
|
|
# for (p1,p2) in [ ("A","B"), ("B","C"), ("C","D"), ("D","A") ]:
|
|
# for (n1,n2) in [ (1,1),(1,2),(3,2),(3,3),(2,3) ,(2,1)]:
|
|
# mbus.addConstr( plays[( p1+str(n1) , p2+str(n2))] == 1)
|
|
|
|
|
|
badExample=False
|
|
|
|
if badExample:
|
|
for p in pots:
|
|
for i in [2,3]:
|
|
mbus.addConstr( plays[( p+str(i-1),p+str(i))]==1)
|
|
# print ( p+str(i-1),p+str(i))
|
|
mbus.addConstr( plays[( p+"3",p+"1")]==1)
|
|
|
|
for p1 in pots:
|
|
for i in [1,2,3]:
|
|
for p2 in pots:
|
|
if p1!=p2:
|
|
# mbus.addConstr( quicksum(plays[( p1+str(i),p2+str(j))] for j in [4,5,6] ) ==2)
|
|
mbus.addConstraint( xp.Sum(plays[( p1+str(i),p2+str(j))] for j in [4,5,6] ) ==2)
|
|
|
|
# mbus.Params.OutputFlag = 0
|
|
mbus.setControl ('outputlog', 0)
|
|
mbus.setControl ('presolve', 0)
|
|
|
|
debug=False
|
|
|
|
|
|
now = datetime.now()
|
|
|
|
nSims=nSimulations
|
|
|
|
# if len(sys.argv)>1:
|
|
# nSims=int(sys.argv[1])
|
|
|
|
|
|
mbus_time = 0
|
|
cal_vartime = 0
|
|
cal_constrtime = 0
|
|
cal_solvetime = 0
|
|
cal_time3 = 0
|
|
report_time = 0
|
|
|
|
solutions =[]
|
|
solution_strings =[]
|
|
for i in range(nSims):
|
|
|
|
ttt = time.time()
|
|
|
|
if i%1000==0:
|
|
with open(f"{logfile}.log", "a") as f:
|
|
f.write(f"{thread}: {i} after {datetime.now()-now}\n")
|
|
f.write(f"\tmbus_time: {mbus_time}\n")
|
|
f.write(f"\tcal_vartime: {cal_vartime}\n")
|
|
f.write(f"\tcal_constrtime: {cal_constrtime}\n")
|
|
f.write(f"\tcal_solvetime: {cal_solvetime}\n")
|
|
f.write(f"\tcal_time3: {cal_time3}\n")
|
|
f.write(f"\treport_time: {report_time}\n")
|
|
|
|
with open(f"{logfile}.txt", "a") as f:
|
|
for s in solutions:
|
|
for s2 in s:
|
|
f.write(s2[0]+s2[1])
|
|
f.write("\n")
|
|
solutions = []
|
|
|
|
cntr+=1
|
|
# mbus.setObjective(quicksum([ int(100*random.random()) * plays[pa] for pa in possAssigns ]))
|
|
mbus.setObjective(xp.Sum([ int(100*random.random()) * plays[pa] for pa in possAssigns ]))
|
|
# mbus.setObjective(quicksum([ max(0,int(pa[0][1]) - int(pa[1][1] )) * plays[pa] for pa in possAssigns ]))
|
|
|
|
# print ("DRAWING !!!!")
|
|
|
|
# mbus.optimize()
|
|
mbus.solve()
|
|
checker_sol = mbus.getSolution(plays)
|
|
|
|
mbus_time += time.time()-ttt
|
|
ttt = time.time()
|
|
sol= [ pa for pa in possAssigns if checker_sol[pa]>0.9]
|
|
solutions.append(sol.copy())
|
|
|
|
report_time += time.time()-ttt
|
|
ttt = time.time()
|
|
|
|
if debug:
|
|
print ("Solution")
|
|
# exit(0)
|
|
print ("INPOT")
|
|
for p in pots:
|
|
print ("")
|
|
print ("POT",p)
|
|
for (t1,t2) in [(t1,t2) for (t1,t2) in sol if t1<t2 and t1[0]==p and t2[0]==p]:
|
|
print ( t1 , "-" , t2)
|
|
|
|
print ("OUTPOT")
|
|
for p in pots:
|
|
print ("")
|
|
print ("POT",p)
|
|
for (t1,t2) in [(t1,t2) for (t1,t2) in sol if t1[0]==p and t2[0]!=p]:
|
|
print ( t1 , "-" , t2)
|
|
|
|
solstring =""
|
|
for pa in possAssigns:
|
|
solstring+= str(int(checker_sol[pa] +0.1) )
|
|
if nSims < 1000:
|
|
solution_strings.append(solstring)
|
|
report_time += time.time()-ttt
|
|
ttt = time.time()
|
|
|
|
mds =range(1,nMatchDays+1)
|
|
|
|
pas2= [ (t1,t2,md) for md in mds for (t1,t2) in sol]
|
|
# print ("pas2", pas2)
|
|
|
|
# cal = Model("Calendar")
|
|
cal = xp.problem("Calendar")
|
|
|
|
# x = cal.addVars(pas2, vtype=GRB.BINARY)
|
|
x = {p:xp.var(vartype=xp.binary) for p in pas2}
|
|
cal.addVariable(x)
|
|
|
|
computeCalendarsHA = True
|
|
computeCalendarsHA = False
|
|
cal_vartime += time.time()-ttt
|
|
ttt = time.time()
|
|
if computeCalendarsHA:
|
|
|
|
pos_patterns = [
|
|
[1,0,1,1,0,0,1,0 ],
|
|
[1,0,1,0,1,0,1,0 ],
|
|
[1,0,1,0,1,0,0,1 ],
|
|
[1,0,1,0,0,1,1,0 ],
|
|
[1,0,1,0,0,1,0,1 ],
|
|
[1,0,0,1,1,0,1,0 ],
|
|
[1,0,0,1,1,0,0,1 ],
|
|
[1,0,0,1,0,1,1,0 ],
|
|
[1,0,0,1,0,1,0,1 ],
|
|
]
|
|
|
|
# add reverse patterns (all those starting with 0,1 )
|
|
pos_patterns+=[ [ 1-p[i] for i in range(8)] for p in pos_patterns ]
|
|
# print ("pos_patterns",pos_patterns)
|
|
|
|
positions = range (len(pos_patterns))
|
|
|
|
# pos = cal.addVars( [(t,p) for t in allTeams for p in positions], vtype=GRB.CONTINUOUS)
|
|
pos = {p:xp.var(vartype=xp.continuous) for p in positions}
|
|
cal.addVariable(pos)
|
|
|
|
for t in allTeams:
|
|
# cal.addConstr( quicksum( [ pos[t,p] for p in positions ]) ==1)
|
|
cal.addConstraint( xp.Sum( [ pos[t,p] for p in positions ]) ==1)
|
|
for md in mds:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 ) == quicksum( [ pos[t,p] for p in positions if pos_patterns[p][md-1]==1 ]) )
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 ) == xp.Sum( [ pos[t,p] for p in positions if pos_patterns[p][md-1]==1 ]) )
|
|
|
|
for (t1,t2) in sol :
|
|
if t1<t2:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] + x[(t2,t1,md)] for md in mds) <=1 )
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] + x[(t2,t1,md)] for md in mds) <=1 )
|
|
|
|
for t in allTeams:
|
|
# every team 4 home games
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 for md in mds ) == 4)
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 for md in mds ) == 4)
|
|
# every team one game a day
|
|
for md in mds:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t in [t1,t2] ) == 1)
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for (t1,t2) in sol if t in [t1,t2] ) == 1)
|
|
|
|
for p in pots:
|
|
for t in getTeamsOfPot[p]:
|
|
for p2 in pots:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 and t2 in getTeamsOfPot[p2] for md in mds ) >= int(0.5*gamesAgainst[(p,p2)]) )
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for (t1,t2) in sol if t ==t1 and t2 in getTeamsOfPot[p2] for md in mds ) >= int(0.5*gamesAgainst[(p,p2)]) )
|
|
else:
|
|
for (t1,t2) in sol :
|
|
if t1<t2:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for md in mds) ==1 )
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for md in mds) ==1 )
|
|
for md in mds:
|
|
# cal.addConstr( x[(t1,t2,md)] == x[(t2,t1,md)] )
|
|
cal.addConstraint( x[(t1,t2,md)] == x[(t2,t1,md)] )
|
|
|
|
for t in activeTeams:
|
|
for md in mds:
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t==t1 ) == 1)
|
|
# cal.addConstr( quicksum(x[(t1,t2,md)] for (t1,t2) in sol if t==t1 ) == 1)
|
|
cal.addConstraint( xp.Sum(x[(t1,t2,md)] for (t1,t2) in sol if t==t1 ) == 1)
|
|
|
|
# cal.setObjective(quicksum( -x[pa] for pa in x.keys() ))
|
|
cal.setObjective(xp.Sum( -x[pa] for pa in x.keys() ))
|
|
|
|
# cal.Params.OutputFlag = 0
|
|
cal.setControl ('outputlog', 0)
|
|
cal.setControl ('presolve', 0)
|
|
# print ("SCHEDULING !!!!")
|
|
|
|
cal_constrtime += time.time()-ttt
|
|
ttt = time.time()
|
|
|
|
# cal.optimize()
|
|
cal.solve()
|
|
|
|
cal_solvetime += time.time()-ttt
|
|
ttt = time.time()
|
|
|
|
# cal_sol= [pa for pa in x.keys() if x[pa].x>0.9 ]
|
|
# print( cal_sol)
|
|
# for pa in cal_sol :
|
|
# print (pa)
|
|
# # print (cal.status)
|
|
# print(cal.objVal)
|
|
|
|
# if cal.status!=2 or cal.objVal>-288:
|
|
if cal.getProbStatus()!=6 or cal.getObjVal()>-288:
|
|
sol= [ (t1,t2) for (t1,t2) in sol if t1<t2]
|
|
# sol= [ (t1,t2) for (t1,t2) in sol if t1[0]=="A" and t2[0]=="D" ]
|
|
print ("No calendar for ", sol)
|
|
print ("Tested " , str(i+1) , " calendars" )
|
|
exit(0)
|
|
|
|
# pas2_sol= [ pas for pas in pas2 if cal.getSolution(x[pas])>0.9]
|
|
# print (pas2_sol)
|
|
|
|
|
|
# showSolution= False
|
|
# showSolution= True
|
|
# if showSolution and debug:
|
|
# for md in mds:
|
|
# print (md,":")
|
|
# for (t1,t2,md2) in pas2_sol:
|
|
# # if md2==md and t1<t2 and "C" in [t1[0],t2[0]] :
|
|
# if md2==md :
|
|
# print (" " ,t1, " -" ,t2)
|
|
|
|
schedule = cal.getSolution(x)
|
|
for t in activeTeams:
|
|
for md in mds:
|
|
if not computeCalendarsHA and sum(schedule[(t1,t2,md)] for (t1,t2) in sol if t==t1 ) < 0.9:
|
|
print ("ALERT ",t,md)
|
|
exit()
|
|
|
|
# print (solutions)
|
|
# oldGm = [ gg for gg in solutions[1] if gg not in solutions[0]]
|
|
# if len(solutions)>1 and showSolution:
|
|
# newGm = [ gg for gg in solutions[-1] if gg not in solutions[-2]]
|
|
|
|
cal_time3 += time.time()-ttt
|
|
ttt = time.time()
|
|
|
|
# print (oldGm)
|
|
# print (newGm)
|
|
|
|
|
|
|
|
n = sys.maxsize
|
|
# n = 2500
|
|
|
|
pool = Pool()
|
|
result = {}
|
|
answer = {}
|
|
threads = cpu_count()
|
|
threads -= 2
|
|
|
|
for cpu in range(threads):
|
|
result[cpu] = pool.apply_async(simulate_craw_and_calendar, args=(f'thread_{cpu}', n,))
|
|
|
|
for cpu in range(threads):
|
|
answer[cpu] = result[cpu].get()
|
|
|