2024-03-13 09:35:38 +01:00

374 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 async_simulate(filename,nSimulations):
nSimulations = 10
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', 1)
debug=False
now = datetime.now()
nSims=nSimulations
if len(sys.argv)>1:
nSims=int(sys.argv[1])
report_time = 0
solutions =[]
solution_strings =[]
nSims = 1
for i in range(nSims):
if i%10==0:
print(i)
# print("report_time:", report_time)
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 !!!!")
sol = [('A1', 'A7'), ('A1', 'A9'), ('A1', 'B2'), ('A1', 'B3'), ('A1', 'C1'), ('A1', 'C2'), ('A1', 'D1'), ('A1', 'D2'), ('A2', 'A3'), ('A2', 'A4'), ('A2', 'B1'), ('A2', 'B4'), ('A2', 'C2'), ('A2', 'C3'), ('A2', 'D1'), ('A2', 'D4'), ('A3', 'A4'), ('A3', 'B3'), ('A3', 'B4'), ('A3', 'C3'), ('A3', 'C4'), ('A3', 'D2'), ('A3', 'D3'), ('A4', 'B1'), ('A4', 'B2'), ('A4', 'C1'), ('A4', 'C4'), ('A4', 'D3'), ('A4', 'D4'), ('A5', 'A8'), ('A5', 'A9'), ('A5', 'B5'), ('A5', 'B9'), ('A5', 'C8'), ('A5', 'C9'), ('A5', 'D6'), ('A5', 'D9'), ('A6', 'A7'), ('A6', 'A8'), ('A6', 'B6'), ('A6', 'B8'), ('A6', 'C5'), ('A6', 'C6'), ('A6', 'D5'), ('A6', 'D6'), ('A7', 'B5'), ('A7', 'B6'), ('A7', 'C5'), ('A7', 'C7'), ('A7', 'D7'), ('A7', 'D8'), ('A8', 'B7'), ('A8', 'B9'), ('A8', 'C8'), ('A8', 'C9'), ('A8', 'D5'), ('A8', 'D7'), ('A9', 'B7'), ('A9', 'B8'), ('A9', 'C6'), ('A9', 'C7'), ('A9', 'D8'), ('A9', 'D9'), ('B1', 'B2'), ('B1', 'B4'), ('B1', 'C2'), ('B1', 'C3'), ('B1', 'D3'), ('B1', 'D4'), ('B2', 'B3'), ('B2', 'C3'), ('B2', 'C4'), ('B2', 'D1'), ('B2', 'D3'), ('B3', 'B4'), ('B3', 'C1'), ('B3', 'C2'), ('B3', 'D2'), ('B3', 'D4'), ('B4', 'C1'), ('B4', 'C4'), ('B4', 'D1'), ('B4', 'D2'), ('B5', 'B8'), ('B5', 'B9'), ('B5', 'C6'), ('B5', 'C7'), ('B5', 'D7'), ('B5', 'D9'), ('B6', 'B7'), ('B6', 'B9'), ('B6', 'C5'), ('B6', 'C8'), ('B6', 'D5'), ('B6', 'D9'), ('B7', 'B8'), ('B7', 'C6'), ('B7', 'C8'), ('B7', 'D6'), ('B7', 'D7'), ('B8', 'C5'), ('B8', 'C9'), ('B8', 'D6'), ('B8', 'D8'), ('B9', 'C7'), ('B9', 'C9'), ('B9', 'D5'), ('B9', 'D8'), ('C1', 'C2'), ('C1', 'C4'), ('C1', 'D3'), ('C1', 'D4'), ('C2', 'C3'), ('C2', 'D1'), ('C2', 'D2'), ('C3', 'C4'), ('C3', 'D1'), ('C3', 'D3'), ('C4', 'D2'), ('C4', 'D4'), ('C5', 'C6'), ('C5', 'C8'), ('C5', 'D5'), ('C5', 'D6'), ('C6', 'C9'), ('C6', 'D7'), ('C6', 'D8'), ('C7', 'C8'), ('C7', 'C9'), ('C7', 'D7'), ('C7', 'D8'), ('C8', 'D6'), ('C8', 'D9'), ('C9', 'D5'), ('C9', 'D9'), ('D1', 'D2'), ('D1', 'D3'), ('D2', 'D4'), ('D3', 'D4'), ('D5', 'D6'), ('D5', 'D8'), ('D6', 'D9'), ('D7', 'D8'), ('D7', 'D9')]
sol2 = []
for (g1,g2) in sol:
mbus.addConstraint(plays[(g1,g2)] == 1)
mbus.addConstraint(plays[(g2,g1)] == 1)
sol2.append((g1,g2))
sol2.append((g2,g1))
# mbus.optimize()
mbus.solve()
checker_sol = mbus.getSolution(plays)
ttt = time.time()
sol= [ pa for pa in possAssigns if checker_sol[pa]>0.9]
print(sorted(sol)==sorted(sol2))
exit()
sol = []
for (a,b) in sol2:
sol.append((a,b))
sol.append((b,a))
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
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.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', 1)
# cal.setControl ('presolveops', 131583)
print ("SCHEDULING !!!!")
# cal.optimize()
cal.solve()
# 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]]
# print (oldGm)
# print (newGm)
# print (solution_strings)
# n = sys.maxsize
# n = 1000
# pool = Pool()
# result = {}
# answer = {}
# # threads = cpu_count()
# threads = 1
# for cpu in range(threads):
# result[cpu] = pool.apply_async(async_simulate, args=(f'thread_{cpu}', n,))
# for cpu in range(threads):
# answer[cpu] = result[cpu].get()
print (len(set(solution_strings)) )
f = open("draw_feasibility/log_"+datetime.now().strftime("%Y%m%d_%H%M%S")+"_"+str(nSims)+".txt", "a")
for s in solutions:
for s2 in s:
f.write(s2[0]+s2[1])
f.write("\n")
f.close()
print ("done" , datetime.now()-now )