research/uefa/feb24_checkandschedule/uefa_tester_24_xpress.py
2024-02-28 16:17:07 +01:00

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()