8457 lines
462 KiB
Python
Executable File
8457 lines
462 KiB
Python
Executable File
# %%
|
|
PROJECT_PATH = '/home/md/Work/ligalytics/leagues_stable/'
|
|
import os, sys
|
|
sys.path.insert(0, PROJECT_PATH)
|
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "leagues.settings")
|
|
|
|
|
|
# XPRESS ENVIRONMENT
|
|
os.environ['XPRESSDIR'] = "/opt/xpressmp_8.4"
|
|
os.environ['XPRESS'] = "/opt/xpressmp_8.4/bin"
|
|
os.environ['LD_LIBRARY_PATH'] = os.environ['XPRESSDIR']+"/lib:"+os.environ['LD_LIBRARY_PATH']
|
|
os.environ['DYLD_LIBRARY_PATH'] = os.environ['XPRESSDIR']+"/lib:"
|
|
os.environ['SHLIB_PATH'] = os.environ['XPRESSDIR']+"/lib:"
|
|
os.environ['LIBPATH'] = os.environ['XPRESSDIR']+"/lib:"
|
|
# os.environ['PYTHONPATH'] =os.environ['XPRESSDIR']+"/lib:"+os.environ['PYTHONPATH']
|
|
os.environ['PYTHONPATH'] =os.environ['XPRESSDIR']+"/lib:"
|
|
os.environ['CLASSPATH'] =os.environ['XPRESSDIR']+"/lib/xprs.jar:"
|
|
os.environ['CLASSPATH'] =os.environ['XPRESSDIR']+"/lib/xprb.jar:"+os.environ['CLASSPATH']
|
|
os.environ['CLASSPATH'] =os.environ['XPRESSDIR']+"/lib/xprm.jar:"+os.environ['CLASSPATH']
|
|
os.environ['PATH'] =os.environ['XPRESSDIR']+"/bin:"+os.environ['PATH']
|
|
|
|
|
|
from leagues import settings
|
|
settings.DATABASES['default']['NAME'] = PROJECT_PATH+'/db.sqlite3'
|
|
|
|
import django
|
|
django.setup()
|
|
|
|
from django.core.files.storage import FileSystemStorage
|
|
from django.utils.translation import gettext as _
|
|
|
|
# from gurobipy import *
|
|
from pulp import *
|
|
from math import sqrt,pow,sin,cos,atan2,pi, ceil
|
|
from collections import defaultdict
|
|
import timeit
|
|
import datetime
|
|
import operator
|
|
import random
|
|
import time
|
|
from os import dup, dup2, close, path
|
|
from importlib import import_module
|
|
import builtins as __builtin__
|
|
import logging
|
|
|
|
from scheduler.models import *
|
|
from leagues.celery import celery, TASK_TIME_LIMIT
|
|
from scheduler.helpers import serialize_scenario
|
|
from scheduler.solver.functions import *
|
|
from scheduler.solver.tasks.optimize_localsearch import smartNeighbor
|
|
|
|
# from research.learners import AttendanceLearner
|
|
from sklearn.model_selection import train_test_split
|
|
from sklearn.ensemble import RandomForestRegressor
|
|
from sklearn.ensemble import GradientBoostingRegressor
|
|
|
|
# %%
|
|
|
|
|
|
task = None
|
|
s2 = 5
|
|
user_name = 'md'
|
|
user_is_staff = True
|
|
runMode = 'NEW'
|
|
localsearch_time = 0
|
|
RUN_ENV = 'local'
|
|
solver = 'xpress'
|
|
|
|
# %%
|
|
|
|
|
|
def optimize_model3 (optCameraMovement):
|
|
|
|
model3 = pulp.LpProblem("League_Scheduling_Model_--_Schedule_Broadcasting_Slots_"+str(thisScenario.id), pulp.LpMaximize)
|
|
# games3 = [ (t1,t2,r,d) for (t1,t2,r,d) in currentSolution if broadcastingNeeds[d]>0 or optCameraMovement]
|
|
games3 = [ (t1,t2,r,d) for (t1,t2,r,d) in currentSolution ]
|
|
# print ("games3")
|
|
# print (games3)
|
|
# print ( print (len(games3)))
|
|
|
|
networkIds=networkName.keys()
|
|
|
|
if optCameraMovement == "TV-Kits" :
|
|
|
|
movements = [(gm1,gm2) for gm1 in games3 for gm2 in games3 if gm2[2]<=gm1[2]+3 and getDateTimeDay[gm1[3]]+datetime.timedelta(days=1)<getDateTimeDay[gm2[3]] ]
|
|
print (len(movements), "movements")
|
|
|
|
if thisLeague.name in ["Indian Super League"] and thisSeason.name not in ["2021", "2022"]:
|
|
minDays = {('Ben', 'Ben'): 0, ('Ben', 'Che'): 1, ('Ben', 'FC '): 2, ('Ben', 'Nor'): 12, ('Ben', 'Jam'): 6, ('Ben', 'Ker'): 2, ('Ben', 'ATK'): 6, ('Ben', 'Mum'): 3, ('Ben', 'Hyd'): 2, ('Ben', 'Odi'): 5, ('Che', 'Ben'): 1, ('Che', 'Che'): 0, ('Che', 'FC '): 3, ('Che', 'Nor'): 11, ('Che', 'Jam'): 5, ('Che', 'Ker'): 2, ('Che', 'ATK'): 5, ('Che', 'Mum'): 4, ('Che', 'Hyd'): 2, ('Che', 'Odi'): 4, ('FC ', 'Ben'): 2, ('FC ', 'Che'): 3, ('FC ', 'FC '): 0, ('FC ', 'Nor'): 14, ('FC ', 'Jam'): 7, ('FC ', 'Ker'): 3, ('FC ', 'ATK'): 7, ('FC ', 'Mum'): 2, ('FC ', 'Hyd'): 2, ('FC ', 'Odi'): 5, ('Nor', 'Ben'): 9, ('Nor', 'Che'): 8, ('Nor', 'FC '): 10, ('Nor', 'Nor'): 0, ('Nor', 'Jam'): 4, ('Nor', 'Ker'): 10, ('Nor', 'ATK'): 3, ('Nor', 'Mum'): 9, ('Nor', 'Hyd'): 7, ('Nor', 'Odi'): 5, ('Jam', 'Ben'): 6, ('Jam', 'Che'): 5, ('Jam', 'FC '): 7, ('Jam', 'Nor'): 5, ('Jam', 'Jam'): 0, ('Jam', 'Ker'): 7, ('Jam', 'ATK'): 1, ('Jam', 'Mum'): 6, ('Jam', 'Hyd'): 5, ('Jam', 'Odi'): 2, ('Ker', 'Ben'): 3, ('Ker', 'Che'): 3, ('Ker', 'FC '): 3, ('Ker', 'Nor'): 14, ('Ker', 'Jam'): 10, ('Ker', 'Ker'): 0, ('Ker', 'ATK'): 10, ('Ker', 'Mum'): 6, ('Ker', 'Hyd'): 5, ('Ker', 'Odi'): 8, ('ATK', 'Ben'): 6, ('ATK', 'Che'): 5, ('ATK', 'FC '): 7, ('ATK', 'Nor'): 5, ('ATK', 'Jam'): 1, ('ATK', 'Ker'): 7, ('ATK', 'ATK'): 0, ('ATK', 'Mum'): 6, ('ATK', 'Hyd'): 5, ('ATK', 'Odi'): 2, ('Mum', 'Ben'): 3, ('Mum', 'Che'): 4, ('Mum', 'FC '): 2, ('Mum', 'Nor'): 12, ('Mum', 'Jam'): 6, ('Mum', 'Ker'): 5, ('Mum', 'ATK'): 6, ('Mum', 'Mum'): 0, ('Mum', 'Hyd'): 3, ('Mum', 'Odi'): 5, ('Hyd', 'Ben'): 2, ('Hyd', 'Che'): 2, ('Hyd', 'FC '): 2, ('Hyd', 'Nor'): 10, ('Hyd', 'Jam'): 5, ('Hyd', 'Ker'): 4, ('Hyd', 'ATK'): 5, ('Hyd', 'Mum'): 3, ('Hyd', 'Hyd'): 0, ('Hyd', 'Odi'): 4, ('Odi', 'Ben'): 5, ('Odi', 'Che'): 4, ('Odi', 'FC '): 5, ('Odi', 'Nor'): 6, ('Odi', 'Jam'): 2, ('Odi', 'Ker'): 6, ('Odi', 'ATK'): 2, ('Odi', 'Mum'): 5, ('Odi', 'Hyd'): 4, ('Odi', 'Odi'): 0}
|
|
minDays = { (t1,t2) : minDays[(getTeamById[t1][:3],getTeamById[t2][:3])] for t1 in teams for t2 in teams }
|
|
movements = [(gm1,gm2) for (gm1,gm2) in movements if (((getDateTimeDay[gm2[3]]-getDateTimeDay[gm1[3]]).total_seconds()/(3600*24))-1) >= minDays[gm1[0],gm2[0]]]
|
|
else:
|
|
movements = [(gm1,gm2) for (gm1,gm2) in movements if distanceById[gm1[0],gm2[0]]/(((getDateTimeDay[gm2[3]]-getDateTimeDay[gm1[3]]).total_seconds()/(3600*24))-1) <350 ]
|
|
|
|
# TV_day_pairs = [ (d1, d2) for d1 in days for d2 in days if getDateTimeDay[d1]<getDateTimeDay[d2] and getDateTimeDay[d1]>=getDateTimeDay[d2] -datetime.timedelta(days=20) ]
|
|
# movements = [ (t1,d1,t2,d2) for t1 in realteams for t2 in realteams for (d1,d2) in TV_day_pairs if getDateTimeDay[d2]-getDateTimeDay[d1] >= datetime.timedelta(days=distanceInDaysById[(t1,t2)]+1 ) ]
|
|
|
|
print (len(movements), "accepted")
|
|
|
|
pred3 ={ gm :[] for gm in games3}
|
|
succ3 ={ gm :[] for gm in games3}
|
|
for (gm1,gm2) in movements :
|
|
pred3[gm2].append(gm1)
|
|
succ3[gm1].append(gm2)
|
|
|
|
br3 = {(t1,t2,d,nw) : pulp.LpVariable('br3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpInteger) \
|
|
for (t1,t2,r,d) in games3 for nw in networkIds }
|
|
unserved = {(t1,t2,r,d) : pulp.LpVariable('unserved_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
for (t1,t2,r,d) in games3 }
|
|
start3 ={((t1,t2,r,d), nw) : pulp.LpVariable('start3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
for (t1,t2,r,d) in games3 for nw in networkIds }
|
|
|
|
move3 = { ((t11,t12,r1,d1) ,(t21,t22,r2,d2),nw) : pulp.LpVariable('move3_'+str(t11)+'_'+str(t12)+'_'+str(d1)+'_'+str(t21)+'_'+str(t22)+'_'+str(d2)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
for ((t11,t12,r1,d1) ,(t21,t22,r2,d2)) in movements for nw in networkIds}
|
|
|
|
for nw in networkIds:
|
|
model3+= lpSum([ start3[gm,nw] for gm in games3 ]) <=1
|
|
|
|
for gm in games3:
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for nw in networkIds])==1 - unserved[gm]
|
|
# model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for nw in networkIds])==1
|
|
for nw in networkIds:
|
|
model3+= br3[gm[0],gm[1],gm[3],nw] == start3[gm,nw] + lpSum([ move3[gm1,gm,nw ] for gm1 in pred3[gm] ])
|
|
model3+= br3[gm[0],gm[1],gm[3],nw] >= lpSum([ move3[gm,gm1,nw ] for gm1 in succ3[gm] ])
|
|
|
|
model3+= - lpSum([ distanceById[gm1[0],gm2[0]] * move3[(gm1,gm2,nw)] for (gm1,gm2) in movements for nw in networkIds ] ) - 100000*lpSum([ unserved[gm] for gm in games3])
|
|
|
|
|
|
# br3 = {(t1,t2,d,nw) : pulp.LpVariable('br3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpInteger) \
|
|
# for (t1,t2,r,d) in games3 for nw in networkIds }
|
|
# start3 = {(t1,t2,d,nw) : pulp.LpVariable('br3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
# for (t1,t2,r,d) in games3 for nw in networkIds }
|
|
|
|
# move3 = { (t11,t12,d1, t21,t22,d2,nw) : pulp.LpVariable('br3_'+str(t11)+'_'+str(t12)+'_'+str(d1)+'_'+str(t21)+'_'+str(t22)+'_'+str(d2)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
# for ( (t11,t12,d1) ,(t21,t22,d2)) in movements for nw in networkIds}
|
|
|
|
# for (t21,t22,r2,d2) in games3:
|
|
# for nw in networkIds:
|
|
# model3+= br3[(t21,t22,d2,nw)]== start3[(t21,t22,d2,nw)] + lpSum([ move[(t11,t12,d1,t21,t22,d2,nw)] for (t11,t12,r1,d1) in pred3[(t21,t22,r2,d2)] ])
|
|
# model3+= br3[(t21,t22,d2,nw)]>= lpSum([ move[(t11,t12,d1,t21,t22,d2,nw)] for (t11,t12,r1,d1) in pred3[(t21,t22,r2,d2)] ])
|
|
|
|
|
|
# for ((t11,t12,r1,d1) , (t21,t22,r2,d2)) in movements :
|
|
# daysInBetween = (getDateTimeDay[d2]-getDateTimeDay[d1]).total_seconds() /(3600*24)
|
|
# distanceInBetween=distanceById[t11,t21]
|
|
# distancePerDay = distanceById[t11,t21]/((getDateTimeDay[d2]-getDateTimeDay[d1]).total_seconds() /(3600*24))
|
|
# print ( distanceById[t11,t21] ,getDateTimeDay[d1],getDateTimeDay[d2], (getDateTimeDay[d2]-getDateTimeDay[d1]).total_seconds() /(3600*24) , distancePerDay )
|
|
# print (len(movements), "movements")
|
|
|
|
# exit(0)
|
|
|
|
if optCameraMovement == "Stadiums" :
|
|
|
|
games3_early = [ (t1,t2,r,d) for (t1,t2,r,d) in games3 if getVal(x_time[(t1,t2,(r,d),getIdByTime["Early"])]) >=0.9]
|
|
games3_late = [ (t1,t2,r,d) for (t1,t2,r,d) in games3 if getVal(x_time[(t1,t2,(r,d),getIdByTime["Late"])]) >=0.9]
|
|
|
|
networkIdByName = { networkName[nw] : nw for nw in networkName.keys() }
|
|
|
|
br3 = {(t1,t2,d,nw) : pulp.LpVariable('br3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpInteger) \
|
|
for (t1,t2,r,d) in games3 for nw in networkIds }
|
|
unserved = {(t1,t2,r,d) : pulp.LpVariable('unserved_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
for (t1,t2,r,d) in games3 }
|
|
|
|
gm3ByDay= {d:[] for d in days}
|
|
gm3ByTeam= {t:[] for t in realteams}
|
|
for gm in games3:
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for nw in networkIds])==1 - unserved[gm]
|
|
# model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for nw in networkIds])==1
|
|
gm3ByDay[gm[3]].append(gm)
|
|
gm3ByTeam[gm[0]].append(gm)
|
|
gm3ByTeam[gm[1]].append(gm)
|
|
|
|
aloneInPune = {(t,r) : pulp.LpVariable('aloneInPune_'+str(t)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) \
|
|
for t in realteams for (t1,t2,r,d) in gm3ByTeam[t]}
|
|
|
|
playInStadium = {(t,r,nw) : lpSum([ br3[(gm[0],gm[1],gm[3],nw)] for gm in gm3ByTeam[t] if gm[2]==r ]) for (t,r) in aloneInPune.keys() for nw in networkIds }
|
|
|
|
for nw in networkIds:
|
|
maxGamesInStadium = 3 if networkName[nw] in ["Brabourne", "MCA Stadium, Pune"] else 4
|
|
print ("MAX GAMES PER TEAM IN ", networkName[nw] , " ", maxGamesInStadium)
|
|
|
|
for d in days:
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for gm in gm3ByDay[d] ] ) <=1
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for d2 in days for gm in gm3ByDay[d2] if getDateTimeDay[d]<=getDateTimeDay[d2] and getDateTimeDay[d2]<= getDateTimeDay[d]+datetime.timedelta(days=2) ] ) <=2
|
|
# print (nw, getDateTimeDay[d] , lpSum([ br3[gm[0],gm[1],gm[3],nw] for d2 in days for gm in gm3ByDay[d2] if getDateTimeDay[d]<=getDateTimeDay[d2] and getDateTimeDay[d2]<= getDateTimeDay[d]+datetime.timedelta(days=2) ] ))
|
|
for t in realteams:
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for gm in gm3ByTeam[t] ] ) <= maxGamesInStadium
|
|
|
|
model3+= lpSum([ br3[gm[0],gm[1],gm[3],nw] for gm in games3_early ] ) <= 4
|
|
|
|
fix3s= [("CSK", "KKR", "2022-03-26", "Wankhede"),
|
|
("MI", "DC", "2022-03-27", "Brabourne"),
|
|
("PBKS", "RCB", "2022-03-27", "DY Patil"),
|
|
("GT", "LSG", "2022-03-28", "Wankhede"),
|
|
("RR", "SRH", "2022-03-29", "MCA Stadium, Pune"),
|
|
]
|
|
if "ipl_only_first_game_fixed" in special_wishes_active:
|
|
fix3s= [("CSK", "KKR", "2022-03-26", "Wankhede")]
|
|
|
|
for (t1, t2, dt, std) in fix3s:
|
|
if t1 in getTeamIdByShortName.keys() and t2 in getTeamIdByShortName.keys() and parse(dt) in getDayByDateTime.keys() and std in networkIdByName.keys():
|
|
print ("fixing in model3 " , (t1, t2, dt, std) )
|
|
t11= getTeamIdByShortName[t1]
|
|
t12= getTeamIdByShortName[t2]
|
|
nwid = networkIdByName[std]
|
|
if (t11, t12, getRoundByDay[getDayByDateTime[parse(dt)]], getDayByDateTime[parse(dt)] ) in games3:
|
|
model3+= br3[t11, t12,getDayByDateTime[parse(dt)],nwid] ==1
|
|
if (t12, t11, getRoundByDay[getDayByDateTime[parse(dt)]], getDayByDateTime[parse(dt)] ) in games3:
|
|
model3+= br3[t12, t11,getDayByDateTime[parse(dt)],nwid] ==1
|
|
|
|
|
|
# - Nachmittagsspiele (Early) gleichmäßig in den drei Stadien außer Pune verteilt - Pune keine Early games
|
|
|
|
# - Pune no Back to Back (keine Spiele an aufeinanderfolgenden Tagen in Pune)- optimalerweise als Special Wish zum An und Ausschalten
|
|
|
|
puneStadiumId = networkIdByName["MCA Stadium, Pune"]
|
|
b2b_vio=0
|
|
|
|
if "limit_b2b" in special_wishes_active:
|
|
sw_type="limit_b2b"
|
|
for nw in networkIds:
|
|
for r in rounds:
|
|
if r<nRounds:
|
|
specialWishItems[sw_type].append((nw,r))
|
|
specialWishVio[(sw_type,nw,r)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(nw)+"_"+str(r), lowBound=0, cat=pulp.LpContinuous)
|
|
model3+= lpSum( [ 0.5*playInStadium[t,r2,nw ] for t in realteams for r2 in [r,r+1] if (t,r2,nw) in playInStadium.keys()] ) <=1+specialWishVio[(sw_type,nw,r)]
|
|
# specialWishItems[sw_type].append(nw)
|
|
specialWishVio[(sw_type,nw)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(nw), lowBound=0, cat=pulp.LpContinuous)
|
|
model3+= lpSum( [ specialWishVio[(sw_type,nw,r)] for r in rounds if r<nRounds] ) <= sw_int1[sw_type] +specialWishVio[(sw_type,nw)]
|
|
b2b_vio += 1*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,nw)] for nw in networkIds ])
|
|
|
|
if "no_b2b_in_pune" in special_wishes_active:
|
|
sw_type="no_b2b_in_pune"
|
|
b2b_pune = {r : pulp.LpVariable('aloneInPune_'+str(r), lowBound = 0, cat = pulp.LpContinuous) for r in rounds }
|
|
for r in rounds:
|
|
if r<nRounds:
|
|
specialWishVio[(sw_type,r,2)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(r) + "_2", lowBound=0, cat=pulp.LpContinuous)
|
|
model3+= lpSum( [ playInStadium[t, r2, puneStadiumId ] for t in realteams for r2 in [r,r+1] if (t,r2,puneStadiumId) in playInStadium.keys()] ) <=2+b2b_pune[r]
|
|
b2b_vio= lpSum([ sw_prio[sw_type]* b2b_pune[r] for r in rounds ])
|
|
|
|
|
|
for (t,r) in aloneInPune.keys():
|
|
punelaterGames = [ r2 for r2 in [r+2,r+3,r+4] if (t,r2) in aloneInPune.keys()]
|
|
punelaterGames = [ r2 for r2 in [r+2,r+3] if (t,r2) in aloneInPune.keys()]
|
|
if len (punelaterGames)>0 and "specialTripsToPune" in special_wishes_active:
|
|
print (getTeamById[t], ": TWO GAMES IN ROUNDS " ,r, r+2)
|
|
model3+= playInStadium[t, r,puneStadiumId ] + sum([ playInStadium[t,r2,puneStadiumId] for r2 in punelaterGames ]) >= 1- 4*aloneInPune[t,r]
|
|
model3+= playInStadium[t, r,puneStadiumId ] - sum([ playInStadium[t,r2,puneStadiumId] for r2 in punelaterGames ]) <= aloneInPune[t,r]
|
|
model3+= -playInStadium[t, r,puneStadiumId ] + sum([ playInStadium[t,r2,puneStadiumId] for r2 in punelaterGames ]) <= aloneInPune[t,r]
|
|
|
|
# Matches at the Pune venue need to be finished by 15th May.
|
|
model3+= lpSum([ br3[(t1,t2,d,networkIdByName["MCA Stadium, Pune"]) ] for (t1,t2,r,d) in games3 if r>51 ]) ==0
|
|
|
|
model3+=( - 100 *lpSum([ unserved[gm] for gm in games3]) - 1 *lpSum([ aloneInPune[tr] for tr in aloneInPune.keys()]) \
|
|
- 20*b2b_vio
|
|
- 100* lpSum([ br3[gm[0],gm[1],gm[3],puneStadiumId] for gm in games3_early ])
|
|
)
|
|
|
|
|
|
if optCameraMovement == "Standard" :
|
|
|
|
|
|
# b_slots[(b.id,r)] = [ (d,str(sl.timeslot.id),sl.quality) for sl in b.slots.all() for d in getDays[r] if getWeekDay[d]==sl.weekday[:3]]
|
|
# b_slots = {b.id : [( sl.weekday , sl.timeslot , sl.quality) for sl in b.slots.all() ] for b in broadcastingwishes}
|
|
# print (b_slots)
|
|
|
|
|
|
getBWish = { bwish.id : bwish for bwish in broadcastingwishes }
|
|
|
|
bWeight = {'A':5, 'B':4, 'C':3}
|
|
possBroadcasts=[]
|
|
bQuality = {}
|
|
|
|
for (t1,t2,r,d) in games3:
|
|
# print ("\nGAME" , t1,t2,r,d)
|
|
for b in broadcastingwishes:
|
|
# print ("CHECKING ", b)
|
|
qual = bWeight[b.quality]* attractivity[t1,t2]
|
|
if t1 in networkFavTeams[b.network.id]:
|
|
qual*=5
|
|
if t2 in networkFavTeams[b.network.id]:
|
|
qual*=4
|
|
for (d1,s,q) in b_slots[(b.id,r)]:
|
|
if d1==d and (not thisSeason.useFeatureKickOffTime or getVal(x_time[(t1,t2,(r,d),s)])>0.9):
|
|
possBroadcasts.append((t1,t2,d,b.id))
|
|
qual*=bWeight[b.quality]/3.0
|
|
if b.network.name== "Super Sport":
|
|
print (" " ,b, getTimeById[s] ,q," does fit ",t1,t2,r, getNiceDay[d], qual, "= x* ",bWeight[b.quality], " * " ,attractivity[t1,t2], getTeamById[t1] , " \t " , getTeamById[t2] , networkFavTeams[b.network.id] , t1 in networkFavTeams[b.network.id] , t2 in networkFavTeams[b.network.id])
|
|
bQuality[(t1,t2,d,b.id)] = qual
|
|
|
|
possBroadCasting2 = list(set(fixedBroadCastingSlots.copy() + [ (t1,t2,d,getBWish[b].network.id) for (t1,t2,d,b) in possBroadcasts]))
|
|
|
|
# print ("bQuality", bQuality)
|
|
|
|
getPossBroadCasting = { fbcs:[] for fbcs in possBroadCasting2 }
|
|
for (t1,t2,d,b) in possBroadcasts:
|
|
getPossBroadCasting[(t1,t2,d,getBWish[b].network.id)].append((t1,t2,d,b))
|
|
|
|
br3_1 = {(t1,t2,d,b) : pulp.LpVariable('br3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(b), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for (t1,t2,d,b) in possBroadcasts }
|
|
br3 = {(t1,t2,d,nw) : pulp.LpVariable('broadcast3_'+str(t1)+'_'+str(t2)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for (t1,t2,d,nw) in possBroadCasting2 }
|
|
|
|
seenTooOften3 = {(t1,bn) : pulp.LpVariable('seenTooOften3_'+str(t1)+'_'+str(bn), lowBound = 0, cat = pulp.LpContinuous) for t1 in teams for bn in varietyNetWorks}
|
|
# slotmissing = {(bn,d) : pulp.LpVariable('slotmissing_'+str(d)+'_'+str(bn), lowBound = 0, cat = pulp.LpContinuous) for d in days for bn in varietyNetWorks}
|
|
|
|
for (t1,t2,d,nw) in possBroadCasting2:
|
|
if len(getPossBroadCasting[ (t1,t2,d,nw) ])>0:
|
|
model3+= br3[ (t1,t2,d,nw) ] == sum([ br3_1[b] for b in getPossBroadCasting[ (t1,t2,d,nw) ] ])
|
|
|
|
print ("Checking networks")
|
|
for bn in varietyNetWorks:
|
|
# print ("network " , bn)
|
|
for t in teams:
|
|
# print ("team " , t)
|
|
relevantGames = [ (t1,t2,d,nw) for (t1,t2,d,nw) in br3.keys() if t in [t1,t2] and b==nw ]
|
|
# print ('relevantGames : ' ,t ,bn , relevantGames)
|
|
model3+= sum([ br3[b] for b in relevantGames ]) <= 1+seenTooOften3[(t,bn)]
|
|
model3+= sum([ br3[b] for b in relevantGames ]) <= 2+0.33*seenTooOften3[(t,bn)]
|
|
model3+= sum([ br3[b] for b in relevantGames ]) <= 4+0.2*seenTooOften3[(t,bn)]
|
|
|
|
for bwish in broadcastingwishes :
|
|
relevantGames = [ b for b in br3_1.keys() if b[3]==bwish.id ]
|
|
thisNetwork = bwish.network.id
|
|
for r in rounds:
|
|
model3 += sum( [br3_1[b1] for b1 in relevantGames if b1[2] in getDays[r] ]) <= bwish.minGames
|
|
if bwish.exclusive:
|
|
for (t1,t2,d,b2) in relevantGames:
|
|
model3 += br3_1[(t1,t2,d,b2) ] + 0.1*sum( [br3[(t1,t2,d,nw)] for nw in networkIds if (t1,t2,d,nw) in br3.keys() and nw!=thisNetwork] ) <= 1
|
|
if bwish.doNotShareWithNetwork.count()>0:
|
|
for (t1,t2,d,b2) in relevantGames:
|
|
model3 += br3_1[(t1,t2,d,b2) ] + sum( [br3[(t1,t2,d,nw2.id)] for nw2 in bwish.doNotShareWithNetwork.all() if (t1,t2,d,nw2.id) in br3.keys() and nw2.id!=thisNetwork ] ) <= 1
|
|
|
|
|
|
|
|
model3+= (
|
|
sum([(1000+ bQuality[(t1,t2,d,b)])*br3_1[(t1,t2,d,b)] for (t1,t2,d,b) in br3_1.keys()])
|
|
# -10*sum([seenTooOften3[(t,bn)] for bn in varietyNetWorks for t in teams])
|
|
-1000000*sum([1-br3[ttdb] for ttdb in fixedBroadCastingSlots])
|
|
)
|
|
|
|
# model3.solve()
|
|
print ('###################')
|
|
print ('# SOLVING MODEL 3 #')
|
|
print ('###################')
|
|
|
|
if RUN_ENV == 'celery' and task:
|
|
task.update_state(state='Solving Model 3', meta={'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
|
|
if solver == "CBC":
|
|
model3.solve(PULP_CBC_CMD(fracGap = 0.1, maxSeconds = 50, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model3.solve(GUROBI(MIPGap=0.1, TimeLimit=500))
|
|
else:
|
|
try:
|
|
model3.solve(XPRESS(msg=1,maxSeconds = 500, targetGap=0.1,options=["THREADS=12"], keepFiles=True))
|
|
except:
|
|
model3.status = pulp.LpStatusNotSolved
|
|
|
|
if model3.status<0:
|
|
writeProgress("Model infeasible.....", thisScenario.id,0)
|
|
if RUN_ENV == 'celery' and task:
|
|
return {'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)}
|
|
else:
|
|
return 'Model could not be solved'
|
|
|
|
# tv_dist=0.0
|
|
# for nw in networkIds:
|
|
# for (gm1,gm2) in movements:
|
|
# if getVal(move3[(gm1,gm2,nw)])>0.1:
|
|
# print ("MOVE3 ", distanceById[gm1[0],gm2[0]], " \t" , getVal(move3[(gm1,gm2,nw)]) , gm1, gm2)
|
|
# tv_dist+=distanceById[gm1[0],gm2[0]]
|
|
# print (tv_dist)
|
|
|
|
lo = ""
|
|
if isinstance(last_objective,(int,float)):
|
|
lo= " (" + str(int(0.01+last_objective-1)) +")"
|
|
feedback = "Done!"+ lo+"<br>"
|
|
for (t1,t2,d) in fixedGames:
|
|
if fixedGameVio[(t1,t2,d)].value() >0.9:
|
|
feedback += '<br>Not fixed :' +getDayById[d]['day'] +' : '+getTeamById[t1] + ' - ' + getTeamById[t2]
|
|
for (t1,t2,d) in fixedGames2:
|
|
if fixedGame2Vio[(t1,t2,d)].value() >0.9:
|
|
feedback += '<br>Not fixed :' +getDayById[d]['day'] +' : '+getTeamById[t1] + ' - ' + getTeamById[t2]
|
|
for (t1,t2) in realgames:
|
|
if missingGamesVio[(t1,t2)].value() >0.9:
|
|
feedback += 'Game missing : '+getTeamById[t1] + ' - ' + getTeamById[t2] + '<br> '
|
|
writeProgress(feedback , thisScenario.id ,100)
|
|
|
|
print ('Solved Broadcasting')
|
|
|
|
|
|
# print ("resiult")
|
|
# for (t1,t2,d,b) in br3.keys() :
|
|
# if br3[(t1,t2,d,b)].value()>0:
|
|
# print ( (100+ bWeight[getBWish[b]['quality']]*attractivity[t1,t2]), t1,t2,d,b, br3[(t1,t2,d,b)].value() )
|
|
|
|
# print ("seen")
|
|
# for bn in varietyNetWorks :
|
|
# for t in teams:
|
|
# if seenTooOften3[(t,bn)].value()>0:
|
|
# print (t, bn, seenTooOften3[(t,bn)].value())
|
|
|
|
|
|
broadcastingResult = [ b for b in br3.keys() if br3[b].value()>0.9 ]
|
|
|
|
def g_tms2(ttdn):
|
|
return getDateTimeDay[ttdn[2]]
|
|
broadcastingResult= sorted(broadcastingResult, key=g_tms2)
|
|
|
|
# print ("broadcastingResult", broadcastingResult)
|
|
# print ("lens ",len(games3), len (broadcastingResult))
|
|
networks_by_game ={(t1,t2,d) : [] for t1 in teams for t2 in teams for d in days}
|
|
|
|
if optCameraMovement in ["TV-Kits", "Stadiums"]:
|
|
# networks_by_game ={(t1,t2,d) : [st] for (t1,t2,d,st) in broadcastingResult}
|
|
for (t1,t2,d,st) in broadcastingResult:
|
|
networks_by_game[(t1,t2,d)].append(st)
|
|
# print ("appending " , t1,t2,d,st,networks_by_game[(t1,t2,d)])
|
|
broadcastingResult =[]
|
|
if optCameraMovement == "Standard" :
|
|
for (t1,t2,d,nw) in broadcastingResult:
|
|
networks_by_game[(t1,t2,d)].append(nw)
|
|
|
|
# print ("networks_by_game", networks_by_game)
|
|
|
|
return broadcastingResult,networks_by_game
|
|
|
|
|
|
# %%
|
|
|
|
thisScenario = Scenario.objects.get(id = s2)
|
|
thisSeason = thisScenario.season
|
|
thisLeague = thisSeason.league
|
|
|
|
mathModelName=thisLeague.name
|
|
if thisSeason.optimizationParameters!="":
|
|
mathModelName=thisSeason.optimizationParameters
|
|
|
|
start_time = time.time()
|
|
|
|
if RUN_ENV == 'celery':
|
|
if task:
|
|
task.update_state(state='Computation started', meta={'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
filename = thisScenario.log_file
|
|
|
|
fileh = logging.FileHandler('data/'+filename, 'a')
|
|
formatter = logging.Formatter('%(message)s')
|
|
fileh.setFormatter(formatter)
|
|
log = logging.getLogger()
|
|
for hdlr in log.handlers[:]:
|
|
log.removeHandler(hdlr)
|
|
log.addHandler(fileh)
|
|
|
|
fs = FileSystemStorage('data/')
|
|
f = fs.open(filename,'a')
|
|
orig_std_out = dup(1)
|
|
dup2(f.fileno(), 1)
|
|
|
|
def print(*args, **kwargs):
|
|
if RUN_ENV == 'celery':
|
|
log.info(str(" ".join([str(x) for x in args])))
|
|
else:
|
|
return __builtin__.print(*args, **kwargs)
|
|
|
|
writeProgress("Computation started !!", thisScenario.id, 3)
|
|
|
|
lengthScale = 1.0 if thisSeason.lengthUnit=="km" else 0.62
|
|
|
|
|
|
def scaledDistanceString (dd):
|
|
return str(int(lengthScale*dd+0.5))+ " "+ thisSeason.lengthUnit
|
|
|
|
otherScenGames=[]
|
|
if thisSeason.improvementObjective!="--":
|
|
for otherScenario in Scenario.objects.filter(season=thisSeason):
|
|
impObjWeight = 5
|
|
if thisSeason.improvementObjective=="stick to old solutions":
|
|
impObjWeight = -5
|
|
if otherScenario.solutionlist() != [['']]:
|
|
for g in otherScenario.solutionlist():
|
|
otherScenGames.append((int(g[1]),int(g[2]),int(g[3]), impObjWeight ))
|
|
|
|
getGlobalCountry={ gc['uefa']: gc['id'] for gc in GlobalCountry.objects.values() }
|
|
|
|
teamObjects = Team.objects.filter(season=thisSeason,active=True).order_by('position').values()
|
|
teams=[]
|
|
realteams=[]
|
|
faketeams=[]
|
|
importantteams=[]
|
|
shortteams=[]
|
|
t_pos={}
|
|
t_pot={}
|
|
t_color={}
|
|
t_country={}
|
|
t_globalCountry={}
|
|
t_stadium = {}
|
|
t_shortname = {}
|
|
t_usePhases = {}
|
|
t_lon = {}
|
|
t_lat = {}
|
|
t_attractivity ={}
|
|
getTeamById={}
|
|
getTeamIdByName={}
|
|
getTeamIdByShortName={}
|
|
getTeamByName={}
|
|
getStadiumById={}
|
|
teamByShort={}
|
|
top4 = []
|
|
for t in teamObjects:
|
|
# print (t['name'], t['id'])
|
|
teams.append(t['id'])
|
|
shortteams.append(t['shortname'])
|
|
teamByShort[t['shortname']]= t['name']
|
|
getTeamIdByShortName[t['shortname']]=t['id']
|
|
if t['name']!='-':
|
|
realteams.append(t['id'])
|
|
else:
|
|
faketeams.append(t['id'])
|
|
if t['very_important']:
|
|
importantteams.append(t['id'])
|
|
t_country[t['id']]= t['country']
|
|
t_globalCountry[t['id']]= t['globalCountry_id']
|
|
if not t_globalCountry[t['id']] and t_country[t['id']] in getGlobalCountry.keys() :
|
|
t_globalCountry[t['id']] = getGlobalCountry[t_country[t['id']]]
|
|
t_pos[t['name']]= t['position']
|
|
t_color[t['name']]="lightyellow"
|
|
t_pot[t['id']]= t['pot']
|
|
t_stadium[t['id']]=t['stadium']
|
|
t_attractivity[t['id']]=t['attractivity']
|
|
t_lon[t['id']]=t['longitude']
|
|
t_lat[t['id']]=t['latitude']
|
|
t_shortname[t['id']]=t['shortname']
|
|
t_usePhases[t['id']]= thisScenario.usePhases
|
|
getTeamById[t['id']]=t['name']
|
|
getStadiumById[t['id']]=t['stadium']
|
|
getTeamIdByName[t['name']]=t['id']
|
|
getTeamByName[t['name']]=t
|
|
if t['attractivity'] >= thisSeason.topTeamMinCoefficient :
|
|
top4.append(t['id'])
|
|
|
|
inactive_teams=[]
|
|
for t in Team.objects.filter(season=thisSeason,active=False).order_by('position').values():
|
|
inactive_teams.append(t['id'])
|
|
t_attractivity[t['id']]=t['attractivity']
|
|
t_lon[t['id']]=t['longitude']
|
|
t_lat[t['id']]=t['latitude']
|
|
t_country[t['id']]= t['country']
|
|
getTeamById[t['id']]=t['name']
|
|
|
|
|
|
lowerBoundFound = False
|
|
distance ={}
|
|
attractivity ={}
|
|
distanceById={}
|
|
distanceInDaysById={}
|
|
stadium_names = set([t['stadium'] for t in teamObjects if t['stadium']!=''])
|
|
stadium_id={}
|
|
stadium_name={}
|
|
sid=0
|
|
for stadium in stadium_names :
|
|
stadium_name[sid]=stadium
|
|
stadium_id[stadium]=sid
|
|
sid+=1
|
|
stadiums = list(stadium_name.keys())
|
|
teamsOfStadium ={ st:[] for st in stadiums }
|
|
|
|
travelDict= thisSeason.travelDict()
|
|
for t1 in teamObjects:
|
|
if t1['stadium']!='':
|
|
teamsOfStadium[stadium_id[t1['stadium']]].append(t1['id'])
|
|
for t2 in teamObjects:
|
|
# distance[t1['name'],t2['name']] = distanceInKm(t1,t2)
|
|
# print (t1['name'],t2['name'],distance[t1['name'],t2['name']] ," -> ", travelDict[t1['id']][t2['id']]['distance'] )
|
|
distance[t1['name'],t2['name']] = travelDict[t1['id']][t2['id']]['distance']
|
|
distanceById[t1['id'],t2['id']] = distance[t1['name'],t2['name']]
|
|
distanceInDaysById[t1['id'],t2['id']] = int(distance[t1['name'],t2['name']]/350 +0.99)
|
|
attractivity[t1['id'],t2['id']] = int(100*t1['attractivity']*t2['attractivity'])
|
|
|
|
|
|
dayObjects = Day.objects.filter(season=thisSeason).values()
|
|
days = [ d['id'] for d in dayObjects if d['round']>0 ]
|
|
|
|
higherSeasons = thisSeason.higherSeasons()
|
|
higherGames = thisSeason.higherGames()
|
|
|
|
this_season_team_names = list(getTeamByName.keys())
|
|
|
|
higherTeamObjects = Team.objects.filter(season__in=higherSeasons,active=True).values()
|
|
higherDayObjects = Day.objects.filter(season__in=higherSeasons,maxGames__gte=1).values()
|
|
higherTeams = [ t['id'] for t in higherTeamObjects]
|
|
higherTeamsOf={ t: [] for t in teams}
|
|
for t in higherTeamObjects:
|
|
getTeamById[t['id']]=t['name']
|
|
t_country[t['id']]=t['country']
|
|
if t['name'] in this_season_team_names:
|
|
higherTeamsOf[getTeamIdByName[t['name']]].append(t['id'])
|
|
|
|
print ("Teams : " , teams)
|
|
print ("VIP Teams : " , importantteams)
|
|
print ("TOP Teams : " , top4)
|
|
|
|
allConferences = Conference.objects.filter(scenario=s2)
|
|
sharedStadiums = False
|
|
for ff in thisSeason.federationmember.all():
|
|
sharedStadiums= ff.federation.sharedStadiums
|
|
|
|
# print ("\nGroups : ")
|
|
t_conference = {t : 0 for t in teams }
|
|
conf_teams={}
|
|
for c in Conference.objects.filter(scenario=s2,regional=False).order_by('name'):
|
|
# print ("A" , c)
|
|
cteams = c.teams.filter(active=True)
|
|
conf_teams[c.name]=[]
|
|
for t in cteams:
|
|
conf_teams[c.name].append(t.id)
|
|
# print ("group for ", t)
|
|
# if t_conference[t.id]!=0:
|
|
# print (getTeamById[t.id] , " in several groups")
|
|
if t_conference[t.id]==0 or len(cteams)< len(t_conference[t.id].teams.filter(active=True)):
|
|
t_conference[t.id]=c
|
|
# print (" is " , c )
|
|
# for t in set([t for t in teams if t_conference[t]==0 ]):
|
|
# print (" no group " , getTeamById[ t])
|
|
# return ''
|
|
|
|
prioVal ={'A': 25 , 'B': 5 , 'C': 1, 'Hard' : 1000}
|
|
|
|
sw_prio = {}
|
|
sw_float1 = {}
|
|
sw_float2 = {}
|
|
sw_int1 = {}
|
|
sw_int2 = {}
|
|
sw_text = {}
|
|
for sw in SpecialWish.objects.filter(scenario=s2):
|
|
sw_prio[sw.name]=prioVal[sw.prio] if sw.active else 0
|
|
sw_float1[sw.name]=sw.float1
|
|
sw_float2[sw.name]=sw.float2
|
|
sw_int1[sw.name]=sw.int1
|
|
sw_int2[sw.name]=sw.int2
|
|
sw_text[sw.name]=sw.text
|
|
special_wishes=list(sw_prio.keys())
|
|
special_wishes_active = [ sw for sw in special_wishes if sw_prio[sw]>0 ]
|
|
|
|
print (special_wishes_active)
|
|
|
|
noBreakLimitTeams = []
|
|
if "allowManyBreaksInRow" in special_wishes_active :
|
|
noBreakLimitTeams = sw_text["allowManyBreaksInRow"].split(",")
|
|
print (noBreakLimitTeams)
|
|
noBreakLimitTeams = [t for t in teams if getTeamById[t] in noBreakLimitTeams]
|
|
print (noBreakLimitTeams)
|
|
|
|
pairings_tmp = Pairing.objects.filter(scenario=s2, active=True).values()
|
|
pairings_tmp2 = Pairing.objects.filter(scenario__is_published=True, team1__id__in=teams, team2__id__in=higherTeams, active=True).values()
|
|
pairings_tmp3 = Pairing.objects.filter(scenario__is_published=True, team2__id__in=teams, team1__id__in=higherTeams, active=True).values()
|
|
pairings = []
|
|
for p in [ p for p in pairings_tmp if p['team1_id'] in teams and p['team2_id'] in teams+higherTeams ] + [ p for p in pairings_tmp2 ] + [ p for p in pairings_tmp3]:
|
|
if p not in pairings:
|
|
pairings.append(p)
|
|
breaks = Break.objects.filter(season=thisSeason).values()
|
|
blockings_tmp = Blocking.objects.filter(scenario=s2,active=True).values()
|
|
blockings = [ bl for bl in blockings_tmp if bl['team_id'] in teams ]
|
|
|
|
# times = ['Early', 'Late']
|
|
timeObjects = TimeSlot.objects.filter(season=thisSeason).values()
|
|
times = [ str(t['id']) for t in timeObjects]
|
|
getTimeById = {str(t['id']):t['name'] for t in timeObjects}
|
|
getIdByTime = {t['name']:str(t['id']) for t in timeObjects}
|
|
|
|
blocked_arena = {(t,d, tm) : False for t in teams for d in days for tm in ["----"] + times }
|
|
hidden_arena = {(t,d, tm) : False for t in teams for d in days for tm in ["----"] + times }
|
|
nBlockingHome=0
|
|
nBlockingAway=0
|
|
|
|
for bl in blockings:
|
|
if bl['type'] in ["Hide"]:
|
|
hidden_arena[(bl['team_id'],bl['day_id'], bl['time'] )]=True
|
|
|
|
if bl['type'] in ["Home","Hide"]:
|
|
nBlockingHome+=1
|
|
blocked_arena[(bl['team_id'],bl['day_id'], bl['time'] )]=True
|
|
else:
|
|
nBlockingAway+=1
|
|
|
|
nTeams=len(teams)
|
|
nPhases =thisSeason.numPhases
|
|
groupView = thisSeason.groupBased
|
|
|
|
gameCntr={(t1,t2) : 0 for t1 in teams for t2 in teams}
|
|
undirectedGameCntr={(t1,t2) : 0 for t1 in teams for t2 in teams}
|
|
|
|
if thisSeason.useFeatureOpponentMatrix:
|
|
gameRequirements = GameRequirement.objects.filter(season=thisSeason, team1__active=True, team2__active=True)
|
|
# print (len(gameRequirements))
|
|
for gm in gameRequirements:
|
|
if thisSeason.undirectedGames:
|
|
undirectedGameCntr[(gm.team1.id,gm.team2.id)]+=gm.number
|
|
undirectedGameCntr[(gm.team2.id,gm.team1.id)]+=gm.number
|
|
# print ( "found undirected game " , (gm.team1.id,gm.team2.id) , gm.number )
|
|
else:
|
|
gameCntr[(gm.team1.id,gm.team2.id)]+=gm.number
|
|
# print ( "found directed game " , (gm.team1.id,gm.team2.id) , gm.number )
|
|
else:
|
|
for t1 in teams:
|
|
for t2 in teams:
|
|
if t1!=t2:
|
|
gameCntr[(t1,t2)]+=nPhases/2
|
|
|
|
for c in Conference.objects.filter(scenario=s2):
|
|
cteams = c.teams.filter(active=True)
|
|
for t1 in cteams:
|
|
for t2 in cteams:
|
|
if t1!=t2:
|
|
gameCntr[(t1.id,t2.id)]+=c.deltaGames/2
|
|
|
|
for (t1,t2) in gameCntr.keys():
|
|
if gameCntr[(t1,t2)]%1!=0 :
|
|
undirectedGameCntr[(t1,t2)]=1
|
|
gameCntr[(t1,t2)] = int(gameCntr[(t1,t2)])
|
|
|
|
games = [ gm for gm in gameCntr.keys() if gameCntr[gm]+undirectedGameCntr[gm]>0]
|
|
|
|
objectiveFunctionWeights = ObjectiveFunctionWeight.objects.filter(scenario=s2).values()
|
|
|
|
gew={}
|
|
gew['Trips'] = 5
|
|
gew['Derbies'] = 5
|
|
gew['Pairings'] = 5
|
|
for ow in objectiveFunctionWeights:
|
|
gew[ow['name']]= ow['use'] * ow['prio']
|
|
|
|
objectivePrio = 'Breaks'
|
|
if gew['Trips']>gew['Breaks'] :
|
|
objectivePrio = 'Trips'
|
|
|
|
print("objectivePrio:", objectivePrio)
|
|
|
|
specialGameControl= mathModelName in ["Florida State League"]
|
|
|
|
if len(games)==0:
|
|
games = [ (t1,t2) for t1 in teams for t2 in teams if t1!=t2 ]
|
|
specialGameControl=True
|
|
|
|
realgames= [(t1,t2) for (t1,t2) in games if getTeamById[t1]!="-" and getTeamById[t2]!="-"]
|
|
|
|
# nur wenn die solutionlist alle spiele enthält, wird dieser modus aktiviert
|
|
evalRun = ( runMode == "Improve" and localsearch_time==0
|
|
and len(thisScenario.solutionlist())==sum([gameCntr[gm]+0.5*undirectedGameCntr[gm] for gm in realgames]) )
|
|
|
|
opponents = { t: set([]) for t in realteams}
|
|
|
|
for (t1,t2) in games:
|
|
if t1 in realteams and t2 in realteams:
|
|
opponents[t1].add(t2)
|
|
opponents[t2].add(t1)
|
|
|
|
model7 = pulp.LpProblem("FindGameClusters_"+str(thisScenario.id), pulp.LpMinimize)
|
|
gmClusters = range(1,nTeams+2)
|
|
|
|
if nPhases>0 and not thisSeason.useFeatureOpponentMatrix and not specialGameControl:
|
|
gmClusters = range(1,2)
|
|
|
|
print ("gmClusters", gmClusters)
|
|
x7 = {(t,c) : pulp.LpVariable('x7_'+str(t)+'_'+str(c), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t in teams for c in gmClusters}
|
|
|
|
for t in realteams:
|
|
model7+= lpSum([ x7[(t,c)] for c in gmClusters]) ==1
|
|
|
|
for (t1,t2) in gameCntr.keys():
|
|
if gameCntr[(t1,t2)]+undirectedGameCntr[(t1,t2)]==0 and t1!=t2:
|
|
for c in gmClusters:
|
|
model7+= x7[(t1,c)]+ x7[(t2,c)] <=1
|
|
# hätte zu infeas leicht geführt bei NBA, NFL..
|
|
# else:
|
|
# model7+= x7[(t1,c)]== x7[(t2,c)]
|
|
|
|
model7+= lpSum([ c*x7[(t,c)] for (t,c) in x7.keys()])
|
|
|
|
if solver == "CBC":
|
|
model7.solve(PULP_CBC_CMD(threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model7.solve(GUROBI(MIPGap=0.01,msg=1))
|
|
else:
|
|
model7.solve(XPRESS(msg=1, targetGap=0.01, maxSeconds = 100, keepFiles=True))
|
|
|
|
gameClusterTeams = { c : [ t for t in teams if x7[(t,c)].value()>0.01] for c in gmClusters }
|
|
gameClusters=[ c for c in gameClusterTeams.keys() if len(gameClusterTeams[c])>0]
|
|
biggestGroupSize = max([len(gameClusterTeams[c]) for c in gameClusters])
|
|
|
|
print ("biggestGroupSize", biggestGroupSize)
|
|
|
|
nPhases = min( [ gameCntr[(t1,t2)]+ gameCntr[(t2,t1)] + undirectedGameCntr[(t1,t2)] for (t1,t2) in realgames ])
|
|
tripStartHeuristicGroupsize = 1 if thisSeason.tripStartHeuristicGroupsize=="None" else int(thisSeason.tripStartHeuristicGroupsize)
|
|
defaultGameRepetions = 1 if not mathModelName in ["NHL", "NBA"] else 2
|
|
nPhases=max(1,int(nPhases/defaultGameRepetions))
|
|
phases = range(nPhases)
|
|
|
|
useBasicGames = nPhases>0
|
|
|
|
if not useBasicGames:
|
|
print ('no basic games but biggest group size ', biggestGroupSize, ' in nPhases ' , nPhases )
|
|
|
|
nRounds = thisSeason.nRounds
|
|
rounds=range(1,nRounds+1)
|
|
|
|
# nRoundsPerPhase= 1
|
|
# if nPhases>0:
|
|
nRoundsPerPhase= int(nRounds/nPhases)
|
|
|
|
print ('nRounds ',nRounds)
|
|
print ('nPhases ',nPhases)
|
|
print ('nRoundsPerPhase ',nRoundsPerPhase)
|
|
print ('defaultGameRepetions ',defaultGameRepetions)
|
|
print ('tripStartHeuristicGroupsize ',tripStartHeuristicGroupsize)
|
|
|
|
script =thisSeason.optimizationScript
|
|
if script == '' :
|
|
if useBasicGames:
|
|
script += "HEURISTIC\n"
|
|
script += "GAME;1-"+str(nRounds)+";0.1;200\n"
|
|
# if nRounds <=10:
|
|
# script += "GAME;1;"+str(nRounds)+"\n"
|
|
# else:
|
|
if thisSeason.groupBased:
|
|
for c in allConferences:
|
|
if not c.regional and c.teams.count() <= 12:
|
|
# print ("### ", c, c.teams.count())
|
|
# print (c, sum([1 for c in c.teams.all()]))
|
|
script += "GROUP;1-"+str(nRounds)+";0.05;30;"+c.name+"\n"
|
|
for cr in range(nPhases):
|
|
minIntRound= min( (cr) * nRoundsPerPhase+1, nRounds)
|
|
maxIntRound= min( (cr+1)*nRoundsPerPhase, nRounds)
|
|
# script += "GROUP;"+ str(minIntRound) + ";"+str(maxIntRound)+";"+str(c.id)+"\n"
|
|
|
|
# for cr in range(nPhases):
|
|
# minIntRound= min( (cr) * nRoundsPerPhase+1, nRounds)
|
|
# maxIntRound= min( (cr+1)*nRoundsPerPhase, nRounds)
|
|
# if len(newRounds)>1:
|
|
# script += "GAME;"+ str(minIntRound) + ";"+str(maxIntRound)+"\n"
|
|
# else:
|
|
# for cr in range(nPhases):
|
|
# minIntRound= min( (cr) * nRoundsPerPhase+1, nRounds)
|
|
# maxIntRound= min( (cr+1)*nRoundsPerPhase, nRounds)
|
|
# newRounds= range(minIntRound,maxIntRound+1)
|
|
# # if nRounds1 > 9 :
|
|
# # script += "HOMEAWAY;"+ str(minIntRound) + ";"+str(maxIntRound)+"\n"
|
|
# # if not useMinRounds:
|
|
# # script += "BASICGAME;"+ str(cr*(nTeams-1)+1) + ";"+str((cr+1)*(nTeams-1))+"\n"
|
|
# if len(newRounds)>1 and False:
|
|
# script += "GAME;"+ str(minIntRound) + ";"+str(maxIntRound)+"\n"
|
|
|
|
script=script.replace('\r', '')
|
|
print ("script")
|
|
print (script)
|
|
optSteps = [ st.split(';') for st in script.split("\n")]
|
|
print (optSteps)
|
|
|
|
script =thisSeason.improvementScript
|
|
if script == '' :
|
|
if thisSeason.groupBased:
|
|
if nRounds >16:
|
|
script += "ROUNDS\n"
|
|
script += "GROUPS\n"
|
|
else:
|
|
# if solver != "CBC":
|
|
# script += "TEAMSROUNDS\n"
|
|
# script += "PAIRS\n"
|
|
script += "TEAMS\n"
|
|
# script += "ROUNDS\n"
|
|
# if solver != "CBC":
|
|
# script += "TEAMSROUNDS\n"
|
|
|
|
impScript=[]
|
|
script=script.replace('\r', '')
|
|
print (script)
|
|
if localsearch_time>0:
|
|
for stall in script.split("\n") :
|
|
st_tok = stall.split(";")
|
|
print (st_tok)
|
|
st=st_tok[0]
|
|
if (st=="GROUPS"):
|
|
print ("ADDING GROUPS")
|
|
onlyUseReoptGroups = False
|
|
for c in allConferences:
|
|
if c.reopt:
|
|
onlyUseReoptGroups = True
|
|
|
|
group_time=30
|
|
if len(st_tok)>1:
|
|
group_time = int(st_tok[1])
|
|
|
|
for c in allConferences:
|
|
tms = [t.id for t in c.teams.filter(active=True)]
|
|
print ("C " , tms)
|
|
if (len(tms) <= 8 or c.reopt) and (not onlyUseReoptGroups or c.reopt):
|
|
print ("C " , tms)
|
|
for tt in tms:
|
|
print ( c.id, " TEAM " , getTeamById[tt])
|
|
# impScript.append((st,1,nRounds, tms, max(30,1.2*nRounds)))
|
|
if nRounds <= 50 or len(tms)<=3:
|
|
# impScript.append((st,1,int(0.75*nRounds),tms, max(group_time,30), ""))
|
|
impScript.append((st,1,nRounds,tms, max(group_time,30), ""))
|
|
else:
|
|
impScript.append((st,1,int(0.5*nRounds),tms, max(group_time,30), ""))
|
|
impScript.append((st,int(0.25*nRounds),int(0.75*nRounds),tms,max(group_time, 30), ""))
|
|
impScript.append((st,int(0.5*nRounds),nRounds, tms, max(group_time,30), ""))
|
|
# impScript.append((st,1,int(0.75*nRounds),tms, max(group_time,300), ""))
|
|
# impScript.append((st,int(0.25*nRounds),nRounds, tms, max(group_time,300), ""))
|
|
# else:
|
|
# if len(tms) <= 8:
|
|
# impScript.append((st,1,int(0.5*nRounds),tms, 30))
|
|
# impScript.append((st,int(0.5*nRounds),nRounds, tms, 30))
|
|
# else:
|
|
# impScript.append((st,1,int(0.25*nRounds),tms, 30))
|
|
# impScript.append((st,int(0.25*nRounds),int(0.5*nRounds),tms, 30))
|
|
# impScript.append((st,int(0.5*nRounds),int(0.75*nRounds),tms, 30))
|
|
# impScript.append((st,int(0.75*nRounds),nRounds, tms, 30))
|
|
|
|
|
|
|
|
if (st=="TEAMS"):
|
|
print ("ADDING TEAMS")
|
|
for t in teams:
|
|
nts=[t]
|
|
if solver != "CBC" and gew['Trips']>=0 and nTeams<=32:
|
|
na = 2 if nTeams*nRounds >200 else 3
|
|
na= random.randint(1,na)
|
|
if len(st_tok)>1:
|
|
na=int(st_tok[1])-1
|
|
for i in range(na):
|
|
# for i in range(4):
|
|
nts.append(teams[random.randint(0,nTeams-1)])
|
|
# print ("adding ", i , nts)
|
|
nts=list(set(nts))
|
|
ctm = len(nts)*15
|
|
if len(st_tok)>2:
|
|
ctm=int(st_tok[2])
|
|
impScript.append((st,1,nRounds,nts, ctm, ""))
|
|
|
|
if (st=="ROUNDS"):
|
|
na=5
|
|
if len(st_tok)>1:
|
|
na=int(st_tok[1])-1
|
|
for r in rounds:
|
|
if r%5==1:
|
|
nrs = random.randint(na,max(na,int(nRounds/6)))
|
|
#dont make time window too big
|
|
nrs = na
|
|
impScript.append((st,r,min(nRounds,r+nrs ),teams, 30, ""))
|
|
|
|
if (st=="ENCOUNTERS"):
|
|
na=10
|
|
if len(st_tok)>1:
|
|
na=int(st_tok[1])-1
|
|
for r in rounds:
|
|
if r%5==1 and r+na <=nRounds :
|
|
impScript.append((st,r,r+na,teams, 30 , "STICKY_HOME") )
|
|
|
|
if (st=="TEAMSROUNDS"):
|
|
for t in teams:
|
|
nts=[t]
|
|
for i in range(8 +2*(t%2)):
|
|
nts.append(teams[random.randint(0,nTeams-1)])
|
|
nts=list(set(nts))
|
|
st = random.randint( 1, nRounds-10 )
|
|
impScript.append((st,st,min(st+12,nRounds),nts, 20, ""))
|
|
# st = random.randint( 1, nRounds-18 )
|
|
# impScript.append((st,st,min(st+18,nRounds),nts, 120, ""))
|
|
|
|
if (st=="PAIRS"):
|
|
for p in pairings:
|
|
impScript.append((st,1,nRounds, [p['team1_id'],p['team2_id']], 20, ""))
|
|
|
|
if (st=="SMART_TEAMS"):
|
|
impTeams = int(st_tok[1]) if len(st_tok) > 1 else 3
|
|
impTime = int(st_tok[2]) if len(st_tok) > 2 else 30
|
|
impScript.append((st,1,nRounds,impTeams,impTime,""))
|
|
if (st=="SMART_ROUNDS"):
|
|
impRounds = int(st_tok[1]) if len(st_tok) > 1 else 5
|
|
impTime = int(st_tok[2]) if len(st_tok) > 2 else 30
|
|
impScript.append((st,1,impRounds,nTeams,impTime,""))
|
|
|
|
|
|
random.shuffle(impScript)
|
|
if runMode=='Improve':
|
|
impScript= [("INIT",1,nRounds, [], 2000, "")] + impScript
|
|
|
|
getPhaseOfRound = { r : min( nPhases-1 , int((r-1)/nRoundsPerPhase)) for r in rounds }
|
|
|
|
if thisSeason.lastRoundOfPhaseOne>0:
|
|
getPhaseOfRound = { r : 0 if r<=thisSeason.lastRoundOfPhaseOne else 1 for r in rounds }
|
|
|
|
getDaysOfPhase = { p : [] for p in phases }
|
|
getDays = { r : [] for r in rounds}
|
|
roundGamesMax = { r : 0 for r in rounds}
|
|
roundGamesMin = { r : 0 for r in rounds}
|
|
getDayById = { d['id'] : d for d in dayObjects}
|
|
getDayByDateTime = { }
|
|
getNiceDayRaw = { d['id'] : d['day'] for d in dayObjects}
|
|
getNiceDay = { d['id'] : d['day'] for d in dayObjects}
|
|
getWeekDay = { d['id'] : '' for d in dayObjects}
|
|
getDateTimeDay = { d['id'] : '' for d in dayObjects}
|
|
getRoundByDay = { d['id'] : d['round'] for d in dayObjects if d['round']>0 }
|
|
getDayMinGames = { d['id'] : d['minGames'] for d in dayObjects if d['round']>0 }
|
|
getDayMaxGames = { d['id'] : d['maxGames'] for d in dayObjects if d['round']>0 }
|
|
getRoundsByDay = { d['id'] : [] for d in dayObjects }
|
|
nDerbies = { d['id'] : [d['nDerbies']] for d in dayObjects}
|
|
roundDays =[]
|
|
roundDaysMin ={ }
|
|
roundDaysMax ={ }
|
|
wds= {0:'Mon', 1:'Tue', 2:'Wed', 3:'Thu', 4:'Fri', 5:'Sat', 6:'Sun'}
|
|
for d in dayObjects:
|
|
if d['round']>0 :
|
|
getRoundsByDay[d['id']].append(d['round'])
|
|
getDays[d['round']].append(d['id'])
|
|
roundDays.append((d['round'],d['id']))
|
|
roundDaysMin[(d['round'],d['id'])]=d['minGames']
|
|
roundDaysMax[(d['round'],d['id'])]=d['maxGames']
|
|
roundGamesMax[d['round']]=min(nTeams/2, roundGamesMax[d['round']]+d['maxGames'] )
|
|
roundGamesMin[d['round']]+=d['minGames']
|
|
ph = getPhaseOfRound[d['round']]
|
|
getDaysOfPhase[ph].append(d['id'])
|
|
if d['round2']>0:
|
|
getRoundsByDay[d['id']].append(d['round2'])
|
|
getDays[d['round2']].append(d['id'])
|
|
roundDays.append((d['round2'],d['id']))
|
|
roundDaysMin[(d['round2'],d['id'])]=d['minGames2']
|
|
roundDaysMax[(d['round2'],d['id'])]=d['maxGames2']
|
|
roundGamesMax[d['round2']]=min(nTeams/2, roundGamesMax[d['round2']]+d['maxGames2'] )
|
|
roundGamesMin[d['round2']]+=d['minGames2']
|
|
|
|
dt = parse(d['day'])
|
|
getDateTimeDay[d['id']] = dt
|
|
getDayByDateTime[dt] = d['id']
|
|
getNiceDay[d['id']] = str(dt.strftime('%a, %b %d, %Y'))
|
|
getWeekDay[d['id']] = str(wds[dt.weekday()])
|
|
|
|
countries = list(set( [t_country[t] for t in teams ]))
|
|
|
|
getWeekDaysPerRound = { r : [ getWeekDay[d] for d in getDays[r]] for r in rounds}
|
|
|
|
wd = {"Mondays":0 , "Tuesdays":1 , "Wednesdays":2 , "Thursdays":3 , "Fridays":4 , "Saturdays":5 , "Sundays":6}
|
|
t_site_bestTimeSlots = { (t,d): [] for t in realteams for d in days }
|
|
prio_weight = { "A" : 0 , "B" : 50 , "C" : 100}
|
|
|
|
|
|
stadiumTimeSlotPreferences = StadiumTimeSlotPreference.objects.filter(team__id__in=teams )
|
|
theseStadiums= set([ stsp.stadiumTimeSlot.stadium for stsp in stadiumTimeSlotPreferences ])
|
|
|
|
teamsInStadium ={st.id: set([]) for st in theseStadiums }
|
|
getSharedStadiumName ={st.id: st.name for st in theseStadiums }
|
|
for stsp in stadiumTimeSlotPreferences:
|
|
teamsInStadium[stsp.stadiumTimeSlot.stadium.id].add(stsp.team.id)
|
|
lonelyTeams = []
|
|
for st in teamsInStadium.keys():
|
|
if len(teamsInStadium[st])==1:
|
|
lonelyTeams+=teamsInStadium[st]
|
|
|
|
incompatible_timslots = {}
|
|
getStadiumTimeSlot= {}
|
|
for st in theseStadiums:
|
|
theseTimeSlots = st.stadiumtimeslots.all().values()
|
|
for ts1 in theseTimeSlots:
|
|
getStadiumTimeSlot[ts1['id']]=ts1
|
|
incompatible_timslots[ts1['id']]=set([])
|
|
if ts1["end"]<=ts1["start"]:
|
|
ts1["end"]=datetime.time(ts1["start"].hour + 2, ts1["start"].minute)
|
|
for ts1 in theseTimeSlots:
|
|
for ts2 in theseTimeSlots:
|
|
if ts1["weekday"]==ts2["weekday"] and ts1["start"]<=ts2["start"] and ts2["start"]<ts1["end"]:
|
|
incompatible_timslots[ts1['id']].add(ts2['id'])
|
|
incompatible_timslots[ts2['id']].add(ts1['id'])
|
|
|
|
# for ts in incompatible_timslots.keys():
|
|
# print ("")
|
|
# print (ts)
|
|
# for t2 in incompatible_timslots[ts]:
|
|
# print (" - " , getStadiumTimeSlot[t2] )
|
|
|
|
# print ("incompatible_timslots", incompatible_timslots)
|
|
|
|
otherGames = [ ( stsb.homeTeam.name, stsb.awayTeam.name, stsb.day, stsb.stadiumTimeSlot.id) for stsb in StadiumTimeSlotBlocking.objects.filter(stadiumTimeSlot_id__in=incompatible_timslots.keys()).exclude(homeTeam_id__in=teams).exclude(homeTeam=None) ]
|
|
# print (len (otherGames),"other games", otherGames)
|
|
|
|
blockedDayGames = { ts :[] for ts in incompatible_timslots.keys() }
|
|
for (h,a,d,ts1) in otherGames:
|
|
# print (d," : " , h," - " , a , " blocks games on " )
|
|
for ts2 in incompatible_timslots[ts1]:
|
|
# print ( " --- " , getStadiumTimeSlot[ts2] )
|
|
blockedDayGames[ts2].append(d)
|
|
|
|
# print ("blockedDayGames", blockedDayGames)
|
|
|
|
stadiumTimeSlotPref = {}
|
|
for stsp in stadiumTimeSlotPreferences:
|
|
t= stsp.team.id
|
|
stadiumTimeSlotPref[(t,stsp.stadiumTimeSlot.id)]=stsp
|
|
blockedDays = [ sb.day for sb in stsp.stadiumTimeSlot.stadiumtimeslotblockings.all().exclude(homeTeam_id__in=teams)]
|
|
for d in days:
|
|
if getDateTimeDay[d].weekday() == wd[stsp.stadiumTimeSlot.weekday] and getNiceDayRaw[d] not in blockedDays + blockedDayGames[stsp.stadiumTimeSlot.id] :
|
|
t_site_bestTimeSlots[(t,d)].append((stsp.prio, stsp.stadiumTimeSlot.id))
|
|
|
|
# if the team is the only one in the stadium, it can focus on the best possible solution
|
|
for t in lonelyTeams:
|
|
for d in days:
|
|
if len(t_site_bestTimeSlots[(t,d)])>1:
|
|
# print (t_site_bestTimeSlots[(t,d)])
|
|
t_site_bestTimeSlots[(t,d)]=sorted(t_site_bestTimeSlots[(t,d)])
|
|
t_site_bestTimeSlots[(t,d)]=t_site_bestTimeSlots[(t,d)][:1]
|
|
# print (" -> " , t_site_bestTimeSlots[(t,d)])
|
|
|
|
# for (t,d) in t_site_bestTimeSlots.keys():
|
|
# if len(t_site_bestTimeSlots[(t,d)])>0:
|
|
# print(getTeamById[t], getNiceDay[d], t_site_bestTimeSlots[(t,d)])
|
|
|
|
toTime=False
|
|
higherLeagueDayIds= []
|
|
upperAndLowerLeagueIds = []
|
|
higherLeagueGetRoundByDay= {d['id']:d['round'] for d in higherDayObjects}
|
|
|
|
for d in higherDayObjects:
|
|
getRoundByDay[d['id']] = 0
|
|
|
|
for d in higherDayObjects:
|
|
dt = parse(d['day'])
|
|
getDateTimeDay[d['id']] = dt
|
|
if dt not in getDayByDateTime.keys():
|
|
getDayByDateTime[dt] = d['id']
|
|
higherLeagueDayIds.append(d['id'])
|
|
getNiceDay[d['id']] = str(dt.strftime('%a, %b %d, %Y'))
|
|
# getRoundByDay[d['id']] = d['round']
|
|
else:
|
|
upperAndLowerLeagueIds.append(getDayByDateTime[dt])
|
|
thisLeagueDay=getDayByDateTime[dt]
|
|
print ("found day in both ", getNiceDay[thisLeagueDay] , " putting in round " , getRoundByDay[thisLeagueDay] )
|
|
for d2 in higherDayObjects :
|
|
if higherLeagueGetRoundByDay[d2['id']] == higherLeagueGetRoundByDay[d['id']]:
|
|
getRoundByDay[d2['id']] = getRoundByDay[thisLeagueDay]
|
|
print ("assigning day ", d2['id'] , d2['day'] , " to round " , getRoundByDay[thisLeagueDay] )
|
|
|
|
getHigherDaysByRound= { r: [d for d in higherLeagueDayIds if getRoundByDay[d]==r ] for r in rounds }
|
|
getHigherDaysByRound[0]= []
|
|
# print (getHigherDaysByRound)
|
|
|
|
|
|
earliestDay={r: getDays[r][0] for r in rounds }
|
|
latestDay={r: getDays[r][0] for r in rounds }
|
|
for r in rounds :
|
|
for d in getDays[r]:
|
|
dt=getDateTimeDay[d]
|
|
if dt>getDateTimeDay[latestDay[r]]:
|
|
latestDay[r]=d
|
|
if dt<getDateTimeDay[earliestDay[r]]:
|
|
earliestDay[r]=d
|
|
|
|
conferences = Conference.objects.filter(scenario=s2).values()
|
|
confTeams = {}
|
|
confName = {}
|
|
confRegional = {}
|
|
for c in Conference.objects.filter(scenario=s2):
|
|
confTeams[c.id] = []
|
|
confName[c.id] = c.name
|
|
confRegional[c.id] = c.regional
|
|
for t in c.teams.filter(active=True):
|
|
confTeams[c.id].append(t.id)
|
|
|
|
basicTeams =[]
|
|
regionalteams = set([])
|
|
regionalConferences=Conference.objects.filter(scenario=s2, regional=True)
|
|
|
|
clusters=[0]
|
|
cluster_teams = {0:[]}
|
|
t_clusters = { t: [] for t in teams }
|
|
for c in regionalConferences:
|
|
clusters.append(c.id)
|
|
cluster_teams[c.id]=[]
|
|
for t in c.teams.filter(active=True):
|
|
cluster_teams[c.id].append(t.id)
|
|
t_clusters[t.id].append(c.id)
|
|
|
|
|
|
for t in teams:
|
|
if len(t_clusters[t])==0:
|
|
cluster_teams[0].append(t)
|
|
# nm=1
|
|
# if len(clusters)>0:
|
|
# nm=max(c for c in clusters )+1
|
|
# clusters.append(nm)
|
|
# cluster_teams[nm]=[t]
|
|
# t_cluster[t]=nm
|
|
|
|
# print ("clusters: ",clusters)
|
|
# print ("t_clusters: ",t_clusters)
|
|
# print ("cluster_teams: ",cluster_teams)
|
|
|
|
|
|
cluster_distances = {}
|
|
|
|
c_weight = { c: 1 for c in clusters }
|
|
|
|
for c1 in clusters:
|
|
for c2 in clusters:
|
|
dist=0
|
|
for t1 in cluster_teams[c1]:
|
|
for t2 in cluster_teams[c2]:
|
|
dist+= distanceById[t1,t2]
|
|
cluster_distances[c1,c2]= int(dist /(max(1,len(cluster_teams[c1]))*max(1,len(cluster_teams[c2]))))
|
|
|
|
if cluster_distances[c1,c1]<100:
|
|
c_weight[c1]= 1.3
|
|
|
|
print ("CLUSTER ", c1)
|
|
for t in cluster_teams[c1]:
|
|
print ("--",getTeamById[t])
|
|
print ("---> Av Distance: ", c1 ,cluster_distances[c1,c1])
|
|
|
|
c_lat = { c: sum([t_lat[t] for t in cluster_teams[c] ])/max(1,len(cluster_teams[c])) for c in clusters }
|
|
c_lon = { c: sum([t_lon[t] for t in cluster_teams[c] ])/max(1,len(cluster_teams[c])) for c in clusters }
|
|
tripToClusterSaving = { (t,c): 2.0*distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c])-cluster_distances[c,c] for t in teams for c in clusters }
|
|
|
|
for c in regionalConferences:
|
|
print (c)
|
|
# print (c.teamlist())
|
|
cteams = c.teams.filter(active=True)
|
|
for t in cteams:
|
|
print (' - ' , t)
|
|
regionalteams.add(t.id)
|
|
|
|
regionalGroupSizes = [ len( c.teams.filter(active=True)) for c in regionalConferences ]
|
|
if len(regionalGroupSizes)>0:
|
|
maxRegionalGroupSize = max([ len( c.teams.filter(active=True)) for c in regionalConferences ] )
|
|
else:
|
|
maxRegionalGroupSize =0
|
|
print ("maxRegionalGroupSize " , maxRegionalGroupSize)
|
|
print ("maxTourLength " , thisSeason.maxTourLength)
|
|
|
|
regionalParent={t : 0 for t in teams}
|
|
regionalKids={t : [] for t in teams}
|
|
|
|
regionalPatternUse=tripStartHeuristicGroupsize>1
|
|
|
|
print("regionalPatternUse", regionalPatternUse)
|
|
|
|
f_team={ t:t for t in teams }
|
|
if regionalPatternUse :
|
|
teamPairs = [ (t1,t2) for (t1,t2) in games if t1<t2]
|
|
print (len(teamPairs))
|
|
# compatibility = {tp :0 for tp in teamPairs}
|
|
compatibility = {(t1,t2) : len([d for d in days if not blocked_arena[(t1,d, "----" )] and not blocked_arena[(t2,d, "----" )]]) for (t1,t2) in teamPairs }
|
|
|
|
# compute regional clusters
|
|
reg_clustersize = tripStartHeuristicGroupsize
|
|
reg_num_clusters = int(nTeams/reg_clustersize+0.9)
|
|
if reg_num_clusters%2==1:
|
|
reg_num_clusters-=1
|
|
reg_clustersize+=1
|
|
|
|
reg_clusters = range(reg_num_clusters)
|
|
# print (reg_clustersize)
|
|
# print (reg_num_clusters)
|
|
# print (reg_clusters)
|
|
minLat = min([ t_lat[t] for t in teams])
|
|
maxLat = max([ t_lat[t] for t in teams])
|
|
minLon = min([ t_lon[t] for t in teams])
|
|
maxLon = max([ t_lon[t] for t in teams])
|
|
c_center_lat= { c: random.uniform(minLat, maxLat) for c in reg_clusters}
|
|
c_center_lon= { c: random.uniform(minLon, maxLon) for c in reg_clusters}
|
|
model_reg1 = pulp.LpProblem("Clustering_--_Regional_1_"+str(thisScenario.id), pulp.LpMinimize)
|
|
reg_edges = [(t1,t2) for t1 in teams for t2 in teams if t1<t2 ]
|
|
reg_x1 = {(t1,t2) : pulp.LpVariable('reg_x_'+str(t1)+'_'+str(t2), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for (t1,t2) in reg_edges}
|
|
|
|
for t1 in teamObjects:
|
|
for t2 in teamObjects:
|
|
if (t1['id'],t2['id']) in reg_edges and t1['stadium']!='' and t1['stadium']==t2['stadium'] :
|
|
reg_x1[(t1['id'],t2['id'])].upBound=0
|
|
print ("forbidding in same group (stadium): " , t1['name'], t2['name'])
|
|
if (t1['id'],t2['id']) in reg_edges and not (t_conference[t1['id']]==t_conference[t2['id']] or '-' in [t1['name'],t2['name']] ) :
|
|
reg_x1[(t1['id'],t2['id'])].upBound=0
|
|
print ("forbidding in same group (conference): " , t1['name'], t2['name'])
|
|
# if t1['name'] =='Winnipeg Jets' and t2['name'] =='Edmonton Oilers':
|
|
# reg_x1[(t1['id'],t2['id'])].lowBound=1
|
|
|
|
for t in teams :
|
|
model_reg1+= sum([ reg_x1[(t1,t2)] for (t1,t2) in reg_edges if t in [t1,t2]]) <=1
|
|
model_reg1+= sum([ reg_x1[(t1,t2)] for (t1,t2) in reg_edges]) ==reg_num_clusters
|
|
print ("NEW OBJECTIVE ")
|
|
comp = sum([ compatibility[(t1,t2)] * reg_x1[(t1,t2)] for (t1,t2) in teamPairs] )
|
|
# model_reg1+= comp
|
|
model_reg1+= sum([ distanceById[t1,t2] * reg_x1[(t1,t2)] for (t1,t2) in reg_edges if not "-" in [getTeamById[t1],getTeamById[t2]]])
|
|
|
|
if solver == "CBC":
|
|
model_reg1.solve(PULP_CBC_CMD(msg=1))
|
|
elif solver == "Gurobi":
|
|
model_reg1.solve(GUROBI(MIPGap=0.0, TimeLimit=120, msg=1))
|
|
else:
|
|
model_reg1.solve(XPRESS(msg=1,maxSeconds=120, keepFiles=True))
|
|
|
|
chosenEdges = [e for e in reg_edges if reg_x1[e].value()>0.9]
|
|
|
|
|
|
# for (t1,t2) in reg_edges:
|
|
# print ([getTeamById[t1],getTeamById[t2]] , distanceInKmByGPS(t_lon[t1],t_lat[t1],t_lon[t2],t_lat[t2]) , "\t " , not "-" in [getTeamById[t1],getTeamById[t2]])
|
|
# for (t1,t2) in chosenEdges:
|
|
# print (" chosen " , getTeamById[t1],getTeamById[t2] , distanceInKmByGPS(t_lon[t1],t_lat[t1],t_lon[t2],t_lat[t2]) , "\t " , not "-" in [getTeamById[t1],getTeamById[t2]] )
|
|
|
|
|
|
print (chosenEdges)
|
|
print (comp.value())
|
|
|
|
|
|
model_reg = pulp.LpProblem("Clustering_--_Regional_"+str(thisScenario.id), pulp.LpMinimize)
|
|
reg_x = {(t,c) : pulp.LpVariable('reg_x_'+str(t)+'_'+str(c), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t in teams for c in reg_clusters}
|
|
for c in reg_clusters:
|
|
model_reg+= sum([ reg_x[(t,c)] for t in teams ])<=reg_clustersize
|
|
model_reg+= sum([ reg_x[(t,c)] for t in teams ])>=2
|
|
(t1,t2) = chosenEdges[c]
|
|
compatibility = sum([1 for d in days if not blocked_arena[(t1,d, "----" )] and not blocked_arena[(t2,d, "----" )] ])
|
|
print ("\nINIT CLUSTER ", getTeamById[t1], ", ", getTeamById[t2] , " ", compatibility )
|
|
for t in [t1,t2]:
|
|
sst= " -- "
|
|
for d in days:
|
|
if blocked_arena[(t,d, "----" )]:
|
|
sst+= "#"
|
|
else:
|
|
sst+= " "
|
|
sst+= " " + getTeamById[t]
|
|
print (sst)
|
|
model_reg+= reg_x[(t1,c)] ==1
|
|
model_reg+= reg_x[(t2,c)] ==1
|
|
c_center_lat[c]= 0.5*(t_lat[t1] + t_lat[t2])
|
|
c_center_lon[c]= 0.5*(t_lon[t1] + t_lon[t2])
|
|
|
|
|
|
for t in teams :
|
|
model_reg+= sum([ reg_x[(t,c)] for c in reg_clusters])==1
|
|
|
|
for i in range(5):
|
|
model_reg+= sum([ distanceInKmByGPS(t_lon[t],t_lat[t],c_center_lon[c],c_center_lat[c]) * reg_x[(t,c)] for t in teams for c in reg_clusters])
|
|
|
|
if solver == "CBC":
|
|
model_reg.solve(PULP_CBC_CMD())
|
|
elif solver == "Gurobi":
|
|
model_reg.solve(GUROBI(MIPGap=0.0, TimeLimit=120, msg=1))
|
|
else:
|
|
model_reg.solve(XPRESS(msg=1,maxSeconds=120, keepFiles=True))
|
|
|
|
for c in reg_clusters:
|
|
# print ("CLUSTER ", c)
|
|
# for t in teams:
|
|
# if reg_x[(t,c)].value()>0.01:
|
|
# print ( getTeamById[t], reg_x[(t,c)].value() , t_lat[t] , t_lon[t] )
|
|
c_center_lat[c]= 0.5*c_center_lat[c] + 0.5*sum ([ t_lat[t] *reg_x[(t,c)].value() for t in teams]) / sum ([reg_x[(t,c)].value() for t in teams])
|
|
c_center_lon[c]= 0.5*c_center_lon[c] + 0.5*sum ([ t_lon[t] *reg_x[(t,c)].value() for t in teams]) / sum ([reg_x[(t,c)].value() for t in teams])
|
|
# print ("new center ",c_center_lat[c], c_center_lon[c] )
|
|
# print ()
|
|
|
|
reg_cluster_teams = { c : [ t for t in teams if reg_x[(t,c)].value()>0.9 ] for c in reg_clusters }
|
|
print (reg_clusters)
|
|
|
|
for c in reg_clusters:
|
|
print ("CLUSTER ", c)
|
|
for t in reg_cluster_teams[c]:
|
|
print ( getTeamById[t], reg_x[(t,c)].value() , t_lat[t] , t_lon[t] )
|
|
father = reg_cluster_teams[c][0]
|
|
basicTeams.append(father)
|
|
for t in reg_cluster_teams[c][1:]:
|
|
if t in realteams:
|
|
regionalParent[t]=father
|
|
regionalKids[father].append(t)
|
|
f_team[t]=father
|
|
|
|
print ("ergebnis")
|
|
print (reg_cluster_teams)
|
|
print (regionalParent)
|
|
print (regionalKids)
|
|
print ()
|
|
|
|
# print ("ALL TEAMS REGIONAL ")
|
|
# for c in regionalConferences:
|
|
# father =0
|
|
# for t in c.teams.filter(active=True):
|
|
# if father ==0:
|
|
# father =t.id
|
|
# basicTeams.append(t.id)
|
|
# else:
|
|
# regionalParent[t.id]=father
|
|
# regionalKids[father].append(t.id)
|
|
# f_team[t.id]=father
|
|
else :
|
|
basicTeams = teams
|
|
|
|
basicGames = [ (t1,t2) for (t1,t2) in games if t1 in basicTeams and t2 in basicTeams ]
|
|
|
|
# print("basicGames",basicGames)
|
|
# print (f_team)
|
|
# print ("basicTeams", basicTeams)
|
|
# print ('parents :')
|
|
# print (regionalParent)
|
|
# print (regionalKids)
|
|
|
|
# for t in basicTeams:
|
|
# if len(regionalKids[t])>0:
|
|
# print (getTeamById[t])
|
|
# for t2 in regionalKids[t]:
|
|
# print (" " ,getTeamById[ t2] , t_conference [t]==t_conference[t2])
|
|
# miniGameSequenceLength = 1
|
|
|
|
nBasicTeams = len (basicTeams)
|
|
nBasicTeamsPerCluster = int(nBasicTeams/len(gameClusters)+0.9)
|
|
if nBasicTeamsPerCluster%2==1:
|
|
nBasicTeamsPerCluster+=1
|
|
|
|
nRounds1 = nBasicTeamsPerCluster-1
|
|
nBasicRounds= nPhases * (nBasicTeamsPerCluster-1)
|
|
|
|
if nBasicTeamsPerCluster==1 or nBasicRounds==1:
|
|
nBasicRounds=nRounds
|
|
nRounds1=nRounds
|
|
|
|
basicRounds = range (1,nBasicRounds+1)
|
|
|
|
print ("nPhases ", nPhases)
|
|
print ("nGameClusters ", len(gameClusters))
|
|
print ("nBasicTeamsPerCluster ", nBasicTeamsPerCluster)
|
|
print ("nBasicTeams ", nBasicTeams)
|
|
print ("nBasicRounds ", nBasicRounds)
|
|
print ("nRounds1 ", nRounds1)
|
|
|
|
stretch = nRounds/nBasicRounds
|
|
# print ("regionalPatternUse " , regionalPatternUse)
|
|
rounds1=range(1,nRounds1+1)
|
|
nGames=nTeams*nRounds1
|
|
|
|
|
|
getBasicRound={ r : int ((r-1)/stretch)+1 for r in rounds}
|
|
getRealRounds = { br : [ r for r in rounds if getBasicRound[r]==br ] for br in basicRounds}
|
|
# print ("stretch : " , stretch)
|
|
|
|
getBasicDays= {r : [] for r in basicRounds}
|
|
for r in rounds:
|
|
getBasicDays[getBasicRound[r]]+=(getDays[r])
|
|
|
|
competitions = {}
|
|
for d in Day.objects.filter(season=thisSeason):
|
|
for comp in d.internationalCompetitions.all():
|
|
dtlb = getDateTimeDay[d.id] - datetime.timedelta(days=comp.nDaysNotPlayBefore)
|
|
dtub = getDateTimeDay[d.id] + datetime.timedelta(days=comp.nDaysNotPlayAfter)
|
|
for d2 in days:
|
|
# dt =parse(getDayById[d2]['day'])
|
|
dt =getDateTimeDay[d2]
|
|
if dtlb<=dt and dt<=dtub:
|
|
for t in comp.teams.filter(active=True):
|
|
# print ("adding ", (t.id,d2) , " for " , comp.name , dtlb , " <= ", dt , " <= ", dtub )
|
|
competitions[(t.id,d2)]=comp.name
|
|
|
|
getRoundDaysByDay = {d: [ rd for rd in roundDays if rd[1]==d ] for d in days}
|
|
getRoundDaysByRound = {r: [rd for rd in roundDays if rd[0]==r ] for r in rounds}
|
|
|
|
daysSorted =[]
|
|
for dt in sorted([ getDateTimeDay[d] for d in days]):
|
|
daysSorted.append ( getDayByDateTime[dt] )
|
|
|
|
minRest = { (t,s1,s2) : thisSeason.minDaysBetweenGames for t in teams for s1 in ['A','H'] for s2 in ['A','H']}
|
|
for t in teamObjects:
|
|
minRest[(t['id'],'H','H')] = max(minRest[(t['id'],'H','H')], t['minRest_HH'] )
|
|
minRest[(t['id'],'H','A')] = max(minRest[(t['id'],'H','A')], t['minRest_HA'] )
|
|
minRest[(t['id'],'A','H')] = max(minRest[(t['id'],'A','H')], t['minRest_AH'] )
|
|
minRest[(t['id'],'A','A')] = max(minRest[(t['id'],'A','A')], t['minRest_AA'] )
|
|
|
|
maxMinRest = { t : max( [ minRest[(t,s1,s2)] for s1 in ['A','H'] for s2 in ['A','H'] ] ) for t in teams }
|
|
|
|
conflictDays = { (t,d) : [d] for d in days+higherLeagueDayIds for t in teams}
|
|
for t in teams:
|
|
for d1 in days+higherLeagueDayIds:
|
|
diffRounds =False
|
|
for d2 in days+higherLeagueDayIds:
|
|
# print (getRoundsByDay[d1],getRoundsByDay[d2],getRoundsByDay[d1]!=getRoundsByDay[d2])
|
|
if getDateTimeDay[d2]>getDateTimeDay[d1] and getDateTimeDay[d2]-getDateTimeDay[d1] <= datetime.timedelta(days=maxMinRest[t]):
|
|
# print (getDateTimeDay[d1],getDateTimeDay[d2], getRoundByDay[d1], getRoundByDay[d2],getDateTimeDay[d2] > getDateTimeDay[d1] , getDateTimeDay[d2]-getDateTimeDay[d1] , datetime.timedelta(days=thisSeason.minDaysBetweenGames))
|
|
conflictDays[(t,d1)].append(d2)
|
|
if d1 in higherLeagueDayIds+upperAndLowerLeagueIds or d2 in higherLeagueDayIds+upperAndLowerLeagueIds or getRoundsByDay[d1]!=getRoundsByDay[d2]:
|
|
diffRounds=True
|
|
|
|
if not diffRounds:
|
|
conflictDays[(t,d1)]=[]
|
|
if len(higherTeamsOf[t])>0 and d1 in upperAndLowerLeagueIds:
|
|
conflictDays[(t,d1)]=[d1]
|
|
|
|
# print (thisScenario.sol_solution)
|
|
|
|
varietyNetWorks=[]
|
|
networkName ={}
|
|
networkFavTeams ={}
|
|
for bn in BroadcastingNetwork.objects.filter(scenario=s2):
|
|
networkName[bn.id] =bn.name
|
|
networkFavTeams[bn.id] = [ t.id for t in bn.teams.all() ]
|
|
if bn.variety:
|
|
varietyNetWorks.append(bn.id)
|
|
|
|
|
|
fixedGames2 = []
|
|
if thisScenario.sol_fixed_games != "":
|
|
for l in [ g.split('_') for g in thisScenario.sol_fixed_games.split('__')]:
|
|
# print (l)
|
|
if int(l[0]) in getRoundsByDay.keys() and int(l[1]) in realteams and int(l[2]) in realteams :
|
|
fixedGames2.append([int(l[1]),int(l[2]),int(l[0]) ])
|
|
|
|
fixedDays=[]
|
|
if thisScenario.sol_fixed_days!= "":
|
|
fixedDays = [ int(g) for g in thisScenario.sol_fixed_days.split('_')]
|
|
|
|
|
|
fixedRounds=[]
|
|
if thisScenario.sol_fixed!='':
|
|
fixedRounds = [ int(g) for g in thisScenario.sol_fixed.split('_')]
|
|
|
|
fixedGames=[]
|
|
currentSolution=[]
|
|
currentAwayLocation = { (t,d) : False for t in teams for d in days}
|
|
currentKickoffTimes = defaultdict(lambda:None)
|
|
|
|
excessGames = { rd: -roundDaysMax[rd] for rd in roundDays }
|
|
deficientGames = { rd: roundDaysMin[rd] for rd in roundDays }
|
|
|
|
fixedBroadCastingSlots = []
|
|
|
|
for l in thisScenario.solutionlist():
|
|
# print ("adding " , l , len(l)>=4 , int(l[0]) in getRoundsByDay.keys() )
|
|
if len(l)>=4 and int(l[0]) in getRoundsByDay.keys() and int(l[1]) in realteams and int(l[2]) in realteams :
|
|
# print (" ++++ ")
|
|
h_id= int(l[1])
|
|
a_id= int(l[2])
|
|
r_id= int(l[3])
|
|
d_id= int(l[0])
|
|
# if len(l)>6 and l[6]!="None" and [h_id,a_id,d_id] in fixedGames2:
|
|
if r_id not in getRoundsByDay[d_id] and len(getRoundsByDay[d_id])>0:
|
|
print ("WRONG ROUND", d_id , " not in round " , r_id, " putting it in round " , getRoundsByDay[d_id][0])
|
|
r_id = getRoundsByDay[d_id][0]
|
|
if (r_id,d_id) in roundDays:
|
|
excessGames[(r_id,d_id)]+=1
|
|
deficientGames[(r_id,d_id)]-=1
|
|
nf = [h_id, a_id, d_id]
|
|
for tm in ["----"] + times :
|
|
if blocked_arena[(h_id,d_id,tm)] :
|
|
print ("Allowing ",tm , "usage of blocked arena of " , getTeamById[h_id] , " at " , getNiceDay[d_id] )
|
|
blocked_arena[(h_id,d_id,tm)]=False
|
|
|
|
if len(intersection(getRoundsByDay[d_id], fixedRounds))>0 :
|
|
fixedGames.append(nf)
|
|
if d_id in fixedDays :
|
|
if not nf in fixedGames2:
|
|
fixedGames2.append(nf)
|
|
if len(l)>=4:
|
|
currentSolution.append([ h_id, a_id, r_id,d_id])
|
|
currentAwayLocation[(a_id,d_id)]=h_id
|
|
if len(l) >= 5:
|
|
if l[4].isnumeric() and l[4] in times:
|
|
currentKickoffTimes[(h_id,a_id,d_id)] = l[4]
|
|
elif l[4] in getIdByTime.keys():
|
|
currentKickoffTimes[(h_id,a_id,d_id)] = getIdByTime[l[4]]
|
|
else:
|
|
currentKickoffTimes[(h_id,a_id,d_id)] = None
|
|
else:
|
|
if len(times)>0:
|
|
currentKickoffTimes[(h_id,a_id,d_id)] = times[0]
|
|
|
|
if len(l)>6 and l[6]!="None" and (evalRun or d_id in fixedDays or [h_id,a_id,d_id] in fixedGames2):
|
|
for nw in l[6].split(";"):
|
|
if int(nw) in networkName.keys():
|
|
fixedBroadCastingSlots.append((h_id,a_id,d_id,int(nw)))
|
|
|
|
excessGames = { rd: max(0,excessGames[rd]) for rd in roundDays }
|
|
deficientGames = { rd: max(0,deficientGames[rd]) for rd in roundDays }
|
|
|
|
print ("currentSolution:")
|
|
print (len(currentSolution))
|
|
print ("fixedGames (nur runde ist wichtig):",len(fixedGames))
|
|
print ("fixedGames2 (datum ist wichtig):",len(fixedGames2))
|
|
|
|
# print ("fixedGames",fixedGames)
|
|
# for ff in fixedGames:
|
|
# print (getNiceDay[ff[2]], "\t",getTeamById[ff[0]],"\t",getTeamById[ff[1]] )
|
|
# print ("fixedGames2",fixedGames2, thisScenario.sol_fixed_games)
|
|
# for ff in fixedGames2:
|
|
# print (getNiceDay[ff[2]], "\t",getTeamById[ff[0]],"\t",getTeamById[ff[1]] )
|
|
|
|
tripElements={t:[] for t in teams}
|
|
trip_minDays={}
|
|
trip_maxDays={}
|
|
trip_prio={}
|
|
for te in TripElement.objects.filter(scenario=s2,active=True):
|
|
trip_minDays[te.id]=te.minDaysBetweenGames
|
|
trip_maxDays[te.id]=te.maxDaysBetweenGames
|
|
trip_prio[te.id]=te.prio
|
|
vt1= [ tt.id for tt in te.visited_teams_first.all()]
|
|
vt2= [ tt.id for tt in te.visited_teams_second.all()]
|
|
vt3= [ tt.id for tt in te.visited_teams_third.all()]
|
|
vt4= [ tt.id for tt in te.visited_teams_fourth.all()]
|
|
for tf in te.travelling_teams.all():
|
|
tripElements[tf.id].append((te.id,vt1,vt2,vt3,vt4))
|
|
|
|
allowed_weekdays={'--' : [0,1,2,3,4,5,6], 'Mondays':[0], 'Tuesdays':[1], 'Wednesdays':[2], 'Thursdays':[3], 'Fridays':[4], 'Saturdays':[5],'Sundays':[6], 'Weekdays':[0,1,2,3,4], 'Weekends':[5,6], 'Mon.-Thu.':[0,1,2,3] , 'Fri.-Sun.':[4,5,6] }
|
|
|
|
hawishes = HAWish.objects.filter(scenario=s2,active=True).order_by('reason').values()
|
|
hawTeams = {}
|
|
hawDays = {}
|
|
hawTimes = {}
|
|
hawRounds = {}
|
|
hawRoundsString = {}
|
|
for c in HAWish.objects.filter(scenario=s2):
|
|
# print ()
|
|
# print (c.reason )
|
|
hawDays[c.id] = []
|
|
hawTeams[c.id] = []
|
|
hawTimes[c.id]= [ str(dd.id) for dd in c.timeslots.all() ]
|
|
if c.selection_mode == 0:
|
|
for t in c.teams.filter(active=True):
|
|
hawTeams[c.id].append(t.id)
|
|
elif c.selection_mode == 1:
|
|
for t in c.groups.all():
|
|
for t2 in t.teams.filter(active=True):
|
|
hawTeams[c.id].append(t2.id)
|
|
elif c.selection_mode == 2:
|
|
cids = [ cn.id for cn in c.countries.all()]
|
|
for t in teams:
|
|
if t_globalCountry[t] in cids:
|
|
hawTeams[c.id].append(t)
|
|
|
|
if c.multidate:
|
|
hawDays[c.id]= [ dd.id for dd in c.dates.all() ]
|
|
# print ("multidate")
|
|
else:
|
|
if c.day and not c.day2:
|
|
hawDays[c.id].append(c.day.id)
|
|
# print('+ ',getDayById[e['day_id']])
|
|
|
|
if not c.day and c.day2:
|
|
hawDays[c.id].append(c.day2.id)
|
|
# print('+ ',getDayById[e['day2_id']])
|
|
|
|
if not c.day and not c.day2:
|
|
for d in days:
|
|
dt = getDateTimeDay[d]
|
|
if dt.weekday() in allowed_weekdays[c.weekdays]:
|
|
# print (hawDays[e['id']])
|
|
hawDays[c.id].append(d)
|
|
# print('+ ',getDayById[d])
|
|
|
|
if c.day and c.day2:
|
|
day1= getDateTimeDay[c.day.id]
|
|
day2= getDateTimeDay[c.day2.id]
|
|
for d in days:
|
|
dt = getDateTimeDay[d]
|
|
# print (day1, "<=" , dt , "<=", day2 , " " , day1<=dt and dt<=day2 )
|
|
if day1<=dt and dt<=day2 and dt.weekday() in allowed_weekdays[c.weekdays]:
|
|
# print (day1, "<=" , dt , "<=", day2 , " " , day1<=dt and dt<=day2 )
|
|
hawDays[c.id].append(d)
|
|
# print('+ ',getDayById[d])
|
|
|
|
print ("processing encounters")
|
|
encwishes = EncWish.objects.filter(scenario=s2,active=True).values()
|
|
encTeams1 = {}
|
|
encTeams2 = {}
|
|
encGroups = {}
|
|
encGames = {}
|
|
encTeams1String = {}
|
|
encTeams2String = {}
|
|
encDays = { e['id'] : [] for e in encwishes}
|
|
encDaySets={}
|
|
encTimes = {}
|
|
encRounds = { e['id'] : [] for e in encwishes}
|
|
encRoundsString = { e['id'] : "" for e in encwishes}
|
|
for c in EncWish.objects.filter(scenario=s2,active=True):
|
|
encTimes[c.id]= [ str(dd.id) for dd in c.timeslots.all() ]
|
|
encTeams1[c.id] = []
|
|
encTeams2[c.id] = []
|
|
encGroups[c.id] = []
|
|
encTeams1String[c.id] = ''
|
|
encTeams2String[c.id] = ''
|
|
for t in c.encounterGroups.all():
|
|
encGroups[c.id].append(t)
|
|
if c.useGroups:
|
|
for gr in c.teams1_groups.all():
|
|
for t in gr.teams.filter(active=True):
|
|
encTeams1[c.id].append(t.id)
|
|
encTeams1String[c.id]+=gr.name +', '
|
|
for gr in c.teams2_groups.all():
|
|
for t in gr.teams.filter(active=True):
|
|
encTeams2[c.id].append(t.id)
|
|
encTeams2String[c.id]+=t.name +', '
|
|
else:
|
|
for t in c.teams1.filter(active=True):
|
|
encTeams1[c.id].append(t.id)
|
|
encTeams1String[c.id]+=t.name +', '
|
|
for t in c.teams2.filter(active=True):
|
|
encTeams2[c.id].append(t.id)
|
|
encTeams2String[c.id]+=t.name +', '
|
|
encTeams1String[c.id] = encTeams1String[c.id][:-2]
|
|
encTeams2String[c.id] = encTeams2String[c.id][:-2]
|
|
|
|
if c.useEncounterGroups:
|
|
tmp_games = [(t1.id,t2.id) for eg in encGroups[c.id] for ec in eg.encounter_set.all() for t1 in ec.homeTeams.all() for t2 in ec.awayTeams.all() if t1!=t2 ]
|
|
tmp_games += [(t2.id,t1.id) for eg in encGroups[c.id] for ec in eg.encounter_set.all() for t1 in ec.homeTeams.all() for t2 in ec.awayTeams.all() if t1!=t2 and ec.symmetry]
|
|
encGames[c.id] = [tmp_games]
|
|
else:
|
|
elemHomeTeams= [encTeams1[c.id]]
|
|
if c.forEachTeam1:
|
|
elemHomeTeams= [ [t] for t in encTeams1[c.id]]
|
|
elemAwayTeams= [ encTeams2[c.id]]
|
|
if c.forEachTeam2:
|
|
elemAwayTeams= [ [t] for t in encTeams2[c.id]]
|
|
encGames[c.id]= []
|
|
# print ("NEW ENC ", elemHomeTeams,elemAwayTeams)
|
|
for elh in elemHomeTeams:
|
|
for ela in elemAwayTeams:
|
|
# print (" --- ENC ", elh,ela)
|
|
tmp_games= [(t1,t2) for t1 in elh for t2 in ela if t1!=t2 ]
|
|
if c.symmetry:
|
|
tmp_games += [(t1,t2) for t1 in ela for t2 in elh if t1!=t2 ]
|
|
encGames[c.id].append( tmp_games)
|
|
|
|
if c.multidate:
|
|
encDays[c.id]= [ dd.id for dd in c.dates.all() ]
|
|
else:
|
|
if c.day:
|
|
day1= getDateTimeDay[c.day.id]
|
|
|
|
if c.day and not c.day2:
|
|
encDays[c.id].append(c.day.id)
|
|
|
|
if not c.day and c.day2:
|
|
encDays[c.id].append(c.day2.id)
|
|
|
|
if not c.day and not c.day2:
|
|
for d in days:
|
|
dt= getDateTimeDay[d]
|
|
# dt = parse(getDayById[d]['day'])
|
|
if dt.weekday() in allowed_weekdays[c.weekdays]:
|
|
encDays[c.id].append(d)
|
|
|
|
if c.day and c.day2:
|
|
# day1= parse(c.day.day)
|
|
# day2= parse(c.day2.day)
|
|
day1= getDateTimeDay[c.day.id]
|
|
day2= getDateTimeDay[c.day2.id]
|
|
for d in days:
|
|
dt= getDateTimeDay[d]
|
|
# dt = parse(getDayById[d]['day'])
|
|
if day1<=dt and dt<=day2 and dt.weekday() in allowed_weekdays[c.weekdays]:
|
|
encDays[c.id].append(d)
|
|
|
|
encDaySets[c.id]=[]
|
|
elemDays= [ encDays[c.id]]
|
|
if c.forEachDay or c.forOneDay:
|
|
elemDays= [ [d] for d in encDays[c.id]]
|
|
|
|
lastDaySet=[]
|
|
for d in elemDays :
|
|
tmpDays=d
|
|
if (c.forEachDay or c.forOneDay) and c.timeframe!=0:
|
|
tmpDays = []
|
|
# day1= parse(getDayById[d[0]]['day'])
|
|
day1= getDateTimeDay[d[0]]
|
|
if c.timeframe>0:
|
|
day2= day1 + datetime.timedelta(days=c.timeframe-1)
|
|
# print (e)
|
|
# print (day1, day2)
|
|
for d3 in days:
|
|
dt= getDateTimeDay[d3]
|
|
# dt = parse(getDayById[d3]['day'])
|
|
if day1<=dt and dt<=day2 :
|
|
tmpDays.append(d3)
|
|
else:
|
|
r1 = getDayById[d[0]]['round']
|
|
for d3 in days:
|
|
# dt = parse(getDayById[d3]['day'])
|
|
dt= getDateTimeDay[d3]
|
|
if day1<=dt and getRoundByDay[d3]< r1 + (-c.timeframe) :
|
|
tmpDays.append(d3)
|
|
# print (" ROUNDWISH ", e, elemEncWishDays[cntr], e['timeframe'])
|
|
# for d4 in elemEncWishDays[cntr]:
|
|
# print (" - " ,getDayById[d4]['day'])
|
|
|
|
if len([ d for d in tmpDays if d not in lastDaySet ])>0:
|
|
encDaySets[c.id].append(tmpDays)
|
|
lastDaySet = tmpDays
|
|
# print("-.--- NEW DAYS", tmpDays)
|
|
|
|
for ds in encDaySets[c.id]:
|
|
for d3 in ds:
|
|
encRounds[c.id]+= getRoundsByDay[d3]
|
|
encRounds[c.id]=sorted(list(set(encRounds[c.id])))
|
|
for r in encRounds[c.id]:
|
|
encRoundsString[c.id]+= str(r)+"_"
|
|
if encRoundsString[c.id]!="":
|
|
encRoundsString[c.id]=encRoundsString[c.id][:-1]
|
|
# print (encRoundsString[c.id] , " # " ,c.affected_rounds , encRoundsString[c.id] != c.affected_rounds)
|
|
|
|
# print(encDays)
|
|
# print (encGames)
|
|
# print (encDaySets)
|
|
# print (encRounds)
|
|
# print (encRoundsString)
|
|
# return ("")
|
|
|
|
seed_games= []
|
|
for enc in encwishes :
|
|
if not enc['useEncounterGroups'] and not enc['useGroups'] and not enc['multidate'] and enc['reason']=="Seed Game" and len(encTeams1[enc['id']])==1 and len(encTeams2[enc['id']])==1 and enc['day_id']:
|
|
seed_games.append((encTeams1[enc['id']][0] ,encTeams2[enc['id']][0] ,enc['day_id']))
|
|
# if blocked_arena[(encTeams1[enc['id']][0], enc['day_id'], "----" )]:
|
|
# print ("SEED GAME IN " , getTeamById[ encTeams1[enc['id']][0]] , " at day ", getNiceDay[enc['day_id']])
|
|
|
|
# must_home = {t : sorted([ r for (h,a,r) in seed_games if h==t]) for t in teams}
|
|
# must_away = {t : sorted([ r for (h,a,r) in seed_games if h==a]) for t in teams}
|
|
# print (seed_games)
|
|
# print ("must_home",must_home)
|
|
# print ("must_away",must_away)
|
|
# exit(0)
|
|
|
|
if runMode=='Improve' and len(thisScenario.solutionlist())>0 :
|
|
oldGameCntr={gm :0 for gm in games }
|
|
for gm in currentSolution:
|
|
if not (gm[0],gm[1]) in oldGameCntr.keys():
|
|
print ("ALERT ", (gm[0],gm[1]) ," not in ", oldGameCntr.keys() )
|
|
else:
|
|
oldGameCntr[(gm[0],gm[1])]+=1
|
|
|
|
unsatisfied_seed_games= [ (h_id,a_id,d_id) for (h_id,a_id,d_id) in seed_games if currentAwayLocation[(a_id,d_id)]!=h_id ]
|
|
missing_gms = [ (t1,t2) for (t1,t2) in realgames if oldGameCntr[(t1,t2)]<gameCntr[(t1,t2)] ]
|
|
missing_imp = [ ("MISSING",1,nRounds,[t1,t2], 30, "") for (t1,t2) in missing_gms]
|
|
seed_imp = [ ("SEED",1,nRounds,[h_id,a_id], 30, "") for (h_id,a_id,d_id) in unsatisfied_seed_games ]
|
|
if thisLeague.name not in ["EuroLeague Basketball"] or True:
|
|
impScript= impScript[:1] + seed_imp+ missing_imp+impScript[1:]
|
|
|
|
print ("missing_imp", missing_imp)
|
|
print ("seed_imp", seed_imp)
|
|
|
|
release_blocking_games = missing_gms
|
|
if len( missing_gms)>0:
|
|
release_blocking_games += realgames
|
|
|
|
for (t1,t2) in release_blocking_games:
|
|
for d in days:
|
|
if not hidden_arena[(t1,d, "----" )] :
|
|
blocked_arena[(t1,d, "----" )]=False
|
|
# print ("FREIGABE ", getTeamById[t1], getNiceDay[ d])
|
|
|
|
|
|
|
|
onlyEarlyDays= []
|
|
onlyLateDays= []
|
|
|
|
if mathModelName=="NBA" and nRounds >34:
|
|
onlyLateDays=[d for d in days if not getWeekDay[d] in ["Sat", "Sun"] and not getNiceDay[d] in ["Fri, Nov 29, 2019", "Wed, Dec 25, 2019" ,"Tue, Dec 31, 2019", "Mon, Jan 20, 2020", "Mon, Jan 24, 2020"] + ["Fri, Dec 25, 2020" ,"Thu, Dec 31, 2020", "Mon, Jan 18, 2021" ] ]
|
|
|
|
# if thisSeason.useFeatureOpponentMatrix:
|
|
# for gm in gameRequirements:
|
|
# # print (gm)
|
|
# if gm.number> 0.5*nPhases:
|
|
# extragames[(gm.team1.id,gm.team2.id)]= gm.number - 0.5*nPhases
|
|
|
|
alwaysConsiderAllGames = not mathModelName in ["Florida State League" , "UEFA NL"]
|
|
|
|
# print (conferences)
|
|
conferencewishes = ConferenceWish.objects.filter(scenario=s2).values()
|
|
|
|
|
|
# print ("encGroups" ,encGroups)
|
|
|
|
|
|
|
|
elemEncWishes ={e['id'] : [] for e in encwishes}
|
|
elemEncWishGames={}
|
|
elemEncWishDays={}
|
|
|
|
cntr=0
|
|
for e in encwishes:
|
|
for eg in encGames[e['id']] :
|
|
for ed in encDaySets[e['id']]:
|
|
if len(eg)>0 and len(ed)>0:
|
|
cntr+=1
|
|
elemEncWishes[e['id']].append(cntr)
|
|
elemEncWishGames[cntr] = eg
|
|
elemEncWishDays[cntr] = ed
|
|
|
|
|
|
# print (elemEncWishGames)
|
|
# print (elemEncWishDays)
|
|
|
|
|
|
encRelRoundsMin = { el :[] for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
encRelRoundsMax = { el :[] for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
|
|
for enc in encwishes:
|
|
# print (e)
|
|
# print ("ENC !! " , enc['reason'] )
|
|
for el in elemEncWishes[enc['id']]:
|
|
relDaysSet = set(elemEncWishDays[el])
|
|
for r in basicRounds :
|
|
if len(relDaysSet.intersection(set(getBasicDays[r])))>0:
|
|
frac = len(relDaysSet.intersection(set(getBasicDays[r]))) / len (getBasicDays[r])
|
|
# print (len(relDaysSet.intersection(set(getBasicDays[r]))) , len (getBasicDays[r]) , frac)
|
|
if frac>0:
|
|
encRelRoundsMin[el].append(r)
|
|
if frac==1:
|
|
encRelRoundsMax[el].append(r)
|
|
|
|
nElemEncWishes = sum ([len(elemEncWishes[enc['id']]) for enc in encwishes])
|
|
|
|
# print (encRelRoundsMin)
|
|
|
|
elemHaWishes ={e['id'] : [] for e in hawishes}
|
|
elemHaWishTeams={}
|
|
elemHaWishDays ={}
|
|
elemHaWishFirstDay ={}
|
|
|
|
cntr =1
|
|
for e in hawishes:
|
|
elemTeams= [ hawTeams[e['id']]]
|
|
if e['forEachTeam']:
|
|
elemTeams= [ [t] for t in hawTeams[e['id']]]
|
|
|
|
elemDays= [ hawDays[e['id']]]
|
|
if e['forEachDay'] or e['forOneDay'] :
|
|
elemDays= [ [d] for d in hawDays[e['id']]]
|
|
|
|
elemHaWishes[e['id']]=[]
|
|
allElemDays=[]
|
|
thisDaySet=[]
|
|
lastDaySet = []
|
|
for d in elemDays :
|
|
# print (e)
|
|
if (e['forEachDay'] or e['forOneDay']) and e['timeframe']!=1:
|
|
thisDaySet=[]
|
|
# day1= parse(getDayById[d[0]]['day'])
|
|
day1= getDateTimeDay[d[0]]
|
|
if e['timeframe']>1:
|
|
day2=day1 + datetime.timedelta(days=e['timeframe']-1)
|
|
for d3 in days:
|
|
# dt = parse(getDayById[d3]['day'])
|
|
dt= getDateTimeDay[d3]
|
|
if day1<=dt and dt<=day2 :
|
|
thisDaySet.append(d3)
|
|
else:
|
|
r1 = getDayById[d[0]]['round']
|
|
for d3 in days:
|
|
dt= getDateTimeDay[d3]
|
|
# dt = parse(getDayById[d3]['day'])
|
|
if day1<=dt and getRoundByDay[d3]< r1 + (-e['timeframe']) :
|
|
thisDaySet.append(d3)
|
|
print (" ROUND HA WISH ", e, thisDaySet, e['timeframe'])
|
|
else:
|
|
thisDaySet=d
|
|
|
|
# only create wish id new day set is superset
|
|
if len([d for d in thisDaySet if d not in lastDaySet])>0:
|
|
for t in elemTeams:
|
|
cntr+=1
|
|
elemHaWishes[e['id']].append(cntr)
|
|
elemHaWishTeams[cntr]=t
|
|
elemHaWishDays[cntr]=thisDaySet.copy()
|
|
elemHaWishFirstDay[cntr]=d[0]
|
|
lastDaySet = thisDaySet.copy()
|
|
allElemDays+= thisDaySet
|
|
|
|
hawRounds[e['id']]=[]
|
|
for d3 in set(allElemDays):
|
|
hawRounds[e['id']]+=getRoundsByDay[d3]
|
|
hawRounds[e['id']]=sorted(list(set(hawRounds[e['id']])))
|
|
hawRoundsString[e['id']]= ""
|
|
for r in hawRounds[e['id']]:
|
|
hawRoundsString[e['id']]+= str(r)+"_"
|
|
if hawRoundsString[e['id']]!="":
|
|
hawRoundsString[e['id']]=hawRoundsString[e['id']][:-1]
|
|
|
|
nElemHaWishes = sum ([len(elemHaWishes[enc['id']]) for enc in hawishes])
|
|
# # print ("nElemHaWishes",nElemHaWishes)
|
|
# print ("hawRounds",hawRounds)
|
|
# print ("hawRoundsString",hawRoundsString)
|
|
|
|
|
|
|
|
# encGroups = EncGroup.objects.filter(scenario=s2).values()
|
|
# derbyRestrictions = DerbyRestriction.objects.filter(scenario=s2).values()
|
|
# fairnessCons = FairnessCon.objects.filter(scenario=s2).values()
|
|
# englishWeeks = EnglishCon.objects.filter(scenario=s2).values()
|
|
# objectiveFunctionWeights = ObjectiveFunctionWeight.objects.filter(scenario=s2).values()
|
|
|
|
# gew={}
|
|
# for ow in objectiveFunctionWeights:
|
|
# gew[ow['name']]= ow['use'] * ow['prio']
|
|
|
|
# print(attractivity)
|
|
# allow={}
|
|
# allow["ATL"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["BKN"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIA", "MIL", "MIN", "NYK", "ORL", "PHI", "TOR", "WAS"]
|
|
# allow["BOS"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIA", "MIL", "MIN", "NYK", "ORL", "PHI", "TOR", "WAS"]
|
|
# allow["CHA"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["CHI"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DEN", "DET", "HOU", "IND", "MEM", "MIL", "MIN", "NOP", "NYK", "OKC", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["CLE"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["DAL"]=["ATL", "CHA", "CHI", "CLE", "DAL", "DEN", "HOU", "IND", "MEM", "MIL", "MIN", "NOP", "OKC", "ORL", "PHX", "SAS", "UTA"]
|
|
# allow["DEN"]=["DAL", "DEN", "GSW", "LAC", "LAL", "MEM", "MIL", "MIN", "OKC", "PHX", "POR", "SAC", "SAS", "UTA"]
|
|
# allow["DET"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "OKC", "ORL", "PHI", "TOR", "WAS"]
|
|
# allow["GSW"]=["DEN", "GSW", "LAC", "LAL", "PHX", "POR", "SAC", "UTA"]
|
|
# allow["HOU"]=["ATL", "CHA", "CHI", "DAL", "DEN", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "OKC", "ORL", "PHX", "SAS", "UTA"]
|
|
# allow["IND"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["LAC"]=["GSW", "LAC", "LAL", "PHX", "POR", "SAC", "UTA"]
|
|
# allow["LAL"]=["GSW", "LAC", "LAL", "PHX", "POR", "SAC", "UTA"]
|
|
# allow["MEM"]=["ATL", "CHA", "CHI", "CLE", "DAL", "DEN", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "OKC", "ORL", "PHI", "SAS", "UTA", "WAS"]
|
|
# allow["MIA"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "HOU", "IND", "MEM", "MIA", "MIL", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "WAS"]
|
|
# allow["MIL"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DEN", "DET", "HOU", "IND", "MEM", "MIL", "MIN", "NOP", "NYK", "OKC", "PHI", "SAS", "TOR", "WAS"]
|
|
# allow["MIN"]=["ATL", "CHA", "CHI", "CLE", "DAL", "DEN", "DET", "HOU", "IND", "MEM", "MIL", "MIN", "NOP", "OKC", "PHI", "PHX", "SAS", "UTA"]
|
|
# allow["NOP"]=["ATL", "CHA", "CHI", "CLE", "DAL", "DEN", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "OKC", "ORL", "PHI", "SAS", "WAS"]
|
|
# allow["NYK"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIA", "MIL", "MIN", "NYK", "ORL", "PHI", "TOR", "WAS"]
|
|
# allow["OKC"]=["ATL", "CHA", "CHI", "CLE", "DAL", "DEN", "DET", "HOU", "IND", "MEM", "MIL", "MIN", "NOP", "OKC", "ORL", "PHX", "SAS", "UTA"]
|
|
# allow["ORL"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DAL", "DET", "HOU", "IND", "MEM", "MIA", "MIL", "NOP", "NYK", "OKC", "ORL", "PHI", "SAS", "WAS"]
|
|
# allow["PHI"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "ORL", "PHI", "TOR", "WAS"]
|
|
# allow["PHX"]=["DAL", "DEN", "GSW", "HOU", "LAC", "LAL", "OKC", "PHX", "POR", "SAC", "SAS", "UTA"]
|
|
# allow["POR"]=["GSW", "LAC", "LAL", "PHX", "POR", "SAC", "UTA"]
|
|
# allow["SAC"]=["DEN", "GSW", "LAC", "LAL", "PHX", "POR", "SAC", "UTA"]
|
|
# allow["SAS"]=["ATL", "CHA", "CHI", "DAL", "DEN", "HOU", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "OKC", "ORL", "PHX", "SAS", "UTA"]
|
|
# allow["TOR"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIL", "MIN", "NYK", "PHI", "TOR", "WAS"]
|
|
# allow["UTA"]=["DAL", "DEN", "GSW", "LAC", "LAL", "MIN", "OKC", "PHX", "POR", "SAC", "SAS", "UTA"]
|
|
# allow["WAS"]=["ATL", "BKN", "BOS", "CHA", "CHI", "CLE", "DET", "IND", "MEM", "MIA", "MIL", "MIN", "NOP", "NYK", "ORL", "PHI", "TOR", "WAS"]
|
|
|
|
# print ("DISTANCES NBA")
|
|
|
|
# shortnames = allow.keys()
|
|
# for testDist in [1825,1850,1875]:
|
|
# maxdist =0
|
|
# mindist =1000000
|
|
# cntr=0
|
|
# for t in shortnames:
|
|
# for t2 in shortnames:
|
|
# thisdist = distance[teamByShort[t],teamByShort[t2]]
|
|
# if t2 in allow[t]:
|
|
# maxdist = max(maxdist,thisdist)
|
|
# if thisdist > testDist:
|
|
# # print ("close : " ,teamByShort[t] , teamByShort[t2] , thisdist )
|
|
# cntr+=1
|
|
# else:
|
|
# mindist = min(mindist,thisdist)
|
|
# if thisdist < testDist:
|
|
# # print ("far : " ,teamByShort[t] , teamByShort[t2] , thisdist )
|
|
# cntr+=1
|
|
# print ("mismatch at " , testDist ," : ", cntr)
|
|
|
|
# print ("maxdist ", maxdist)
|
|
# print ("mindist ", mindist)
|
|
|
|
|
|
|
|
# gameCntr = { (t1,t2) :0 for t1 in shortnames for t2 in shortnames }
|
|
# wantedGames =[('TOR','NOP'), ('LAC','LAL'), ('CHA','CHI'), ('ORL','CLE'), ('IND','DET'), ('PHI','BOS'), ('MIA','MEM'), ('BKN','MIN'), ('SAS','NYK'), ('DAL','WAS'), ('UTA','OKC'), ('POR','DEN'), ('PHX','SAC'), ('DET','ATL'), ('HOU','MIL'), ('GSW','LAC'), ('CHA','MIN'), ('BOS','TOR'), ('BKN','NYK'), ('MEM','CHI'), ('NOP','DAL'), ('OKC','WAS'), ('DEN','PHX'), ('SAC','POR'), ('LAL','UTA'), ('MIL','MIA'), ('DET','PHI'), ('NYK','BOS'), ('ATL','ORL'), ('CLE','IND'), ('HOU','NOP'), ('CHI','TOR'), ('SAS','WAS'), ('UTA','SAC'), ('PHX','LAC'), ('OKC','GSW'), ('MEM','BKN'), ('MIN','MIA'), ('DAL','POR'), ('LAL','CHA'), ('NYK','CHI'), ('DET','IND'), ('TOR','ORL'), ('ATL','PHI'), ('MIL','CLE'), ('NOP','GSW'), ('HOU','OKC'), ('SAS','POR'), ('SAC','DEN'), ('PHX','UTA'), ('LAC','CHA'), ('MIA','ATL'), ('DEN','DAL'), ('LAL','MEM'), ('CLE','CHI'), ('PHI','MIN'), ('ORL','NYK'), ('TOR','DET'), ('BKN','IND'), ('BOS','MIL'), ('WAS','HOU'), ('OKC','POR'), ('SAC','CHA'), ('UTA','LAC'), ('GSW','PHX'), ('ATL','MIA'), ('NOP','DEN'), ('LAC','SAS'), ('IND','CLE'), ('BKN','HOU'), ('ORL','MIL'), ('BOS','NYK'), ('CHI','DET'), ('DAL','LAL'), ('SAC','UTA'), ('GSW','SAS'), ('OKC','NOP'), ('DET','BKN'), ('ORL','DEN'), ('WAS','MIN'), ('MEM','PHX'), ('MIL','TOR'), ('GSW','CHA'), ('POR','PHI'), ('IND','CHI'), ('MIA','HOU'), ('NYK','SAC'), ('SAS','LAL'), ('CLE','DAL'), ('LAC','UTA'), ('WAS','DET'), ('BKN','NOP'), ('MEM','HOU'), ('MIN','MIL'), ('PHX','PHI'), ('GSW','POR'), ('CLE','BOS'), ('CHA','IND'), ('ATL','SAS'), ('CHI','LAL'), ('OKC','ORL'), ('DEN','MIA'), ('DET','NYK'), ('IND','WAS'), ('ATL','CHI'), ('HOU','GSW'), ('TOR','SAC'), ('MEM','MIN'), ('DAL','ORL'), ('UTA','PHI'), ('LAC','MIL'), ('CHA','BOS'), ('SAS','OKC'), ('PHX','MIA'), ('LAC','POR'), ('WAS','CLE'), ('IND','DET'), ('ORL','MEM'), ('ATL','SAC'), ('MIN','GSW'), ('NOP','TOR'), ('DAL','NYK'), ('UTA','MIL'), ('DEN','PHI'), ('POR','BKN'), ('LAL','MIA'), ('SAS','BOS'), ('CHA','NOP'), ('MEM','DAL'), ('OKC','GSW'), ('CHI','HOU'), ('MIN','DEN'), ('PHI','CHA'), ('ORL','IND'), ('OKC','MIL'), ('NYK','CLE'), ('PHX','BKN'), ('POR','ATL'), ('LAL','TOR'), ('DET','MIN'), ('BOS','DAL'), ('NOP','HOU'), ('SAS','MEM'), ('LAC','TOR'), ('GSW','UTA'), ('PHI','CLE'), ('IND','OKC'), ('MIA','DET'), ('CHI','NYK'), ('DEN','ATL'), ('UTA','BKN'), ('PHX','LAL'), ('SAC','POR'), ('CHA','MEM'), ('ORL','PHI'), ('HOU','LAC'), ('BOS','WAS'), ('MIN','SAS'), ('LAL','GSW'), ('POR','TOR'), ('CLE','MIA'), ('MIL','CHI'), ('NYK','DAL'), ('NOP','LAC'), ('PHX','ATL'), ('DEN','BKN'), ('CHA','DET'), ('ORL','SAS'), ('HOU','IND'), ('OKC','PHI'), ('MEM','UTA'), ('MIN','WAS'), ('GSW','BOS'), ('LAL','SAC'), ('CHI','BKN'), ('IND','MIL'), ('NYK','CHA'), ('MIN','HOU'), ('MIA','NOP'), ('SAS','POR'), ('DAL','TOR'), ('LAC','ATL'), ('CLE','PHI'), ('SAC','BOS'), ('MEM','DEN'), ('ORL','WAS'), ('NOP','GSW'), ('LAL','ATL'), ('NYK','CLE'), ('TOR','CHA'), ('BKN','IND'), ('CHI','MIL'), ('HOU','POR'), ('DAL','SAS'), ('PHX','BOS'), ('UTA','MIN'), ('LAC','OKC'), ('MEM','GSW'), ('NOP','POR'), ('SAC','PHX'), ('LAL','OKC'), ('PHI','NYK'), ('WAS','SAS'), ('BKN','CHA'), ('MIA','CLE'), ('DAL','GSW'), ('ATL','MIL'), ('TOR','ORL'), ('CHI','DET'), ('MIN','UTA'), ('DEN','HOU'), ('LAC','BOS'), ('MIL','POR'), ('PHX','NOP'), ('DET','ATL'), ('WAS','CHA'), ('BKN','SAC'), ('OKC','LAL'), ('CHI','MIA'), ('PHI','SAS'), ('DAL','CLE'), ('DEN','BOS'), ('UTA','GSW'), ('LAC','HOU'), ('MIN','PHX'), ('CHA','CHI'), ('IND','ORL'), ('PHI','MIA'), ('NYK','SAS'), ('ATL','TOR'), ('MEM','LAL'), ('CLE','POR'), ('MIL','DET'), ('UTA','NOP'), ('HOU','DAL'), ('NYK','BKN'), ('WAS','SAC'), ('DEN','PHX'), ('LAC','NOP'), ('CLE','BKN'), ('IND','MEM'), ('DET','ORL'), ('MIA','CHA'), ('ATL','MIN'), ('TOR','PHI'), ('BOS','SAC'), ('CHI','POR'), ('MIL','UTA'), ('SAS','LAL'), ('GSW','OKC'), ('DAL','LAC'), ('DEN','WAS'), ('BOS','BKN'), ('CHA','DET'), ('CLE','ORL'), ('PHI','SAC'), ('IND','UTA'), ('TOR','NYK'), ('MIL','ATL'), ('MEM','LAC'), ('HOU','MIA'), ('SAS','MIN'), ('PHX','WAS'), ('NOP','LAL'), ('POR','OKC'), ('GSW','CHI'), ('BKN','BOS'), ('DET','CHA'), ('ORL','TOR'), ('CLE','MIL'), ('NYK','PHI'), ('IND','ATL'), ('MIA','GSW'), ('OKC','NOP'), ('MEM','UTA'), ('SAS','LAC'), ('PHX','DAL'), ('POR','CHI'), ('LAL','WAS'), ('SAC','DEN'), ('PHI','IND'), ('HOU','ATL'), ('MIL','CHA'), ('BKN','MIA'), ('NYK','BOS'), ('MIN','MEM'), ('LAL','DAL'), ('NOP','OKC'), ('DET','SAS'), ('ORL','GSW'), ('TOR','UTA'), ('LAC','WAS'), ('CHA','PHX'), ('PHI','UTA'), ('ATL','GSW'), ('MEM','IND'), ('MIL','NYK'), ('SAC','CHI'), ('CLE','DET'), ('WAS','ORL'), ('NOP','DAL'), ('TOR','MIA'), ('SAS','HOU'), ('DEN','LAL'), ('LAC','POR'), ('CHA','GSW'), ('DET','MIL'), ('ORL','PHX'), ('ATL','BKN'), ('BOS','MIA'), ('OKC','IND'), ('CHI','MEM'), ('DAL','MIN'), ('UTA','LAL'), ('POR','SAC'), ('WAS','PHI'), ('NYK','DEN'), ('TOR','HOU'), ('NOP','PHX'), ('CHA','BKN'), ('DET','IND'), ('CLE','ORL'), ('BOS','DEN'), ('CHI','GSW'), ('OKC','MIN'), ('MIA','WAS'), ('MIL','LAC'), ('SAS','SAC'), ('POR','LAL'), ('DAL','NOP'), ('PHI','CLE'), ('NYK','IND'), ('HOU','PHX'), ('UTA','MEM'), ('BKN','DEN'), ('CHA','ATL'), ('MIA','CHI'), ('WAS','LAC'), ('PHI','TOR'), ('DAL','SAC'), ('POR','OKC'), ('LAL','MIN'), ('IND','LAC'), ('BOS','CLE'), ('NOP','DET'), ('MIL','ORL'), ('HOU','SAC'), ('CHI','TOR'), ('PHX','MIN'), ('UTA','OKC'), ('GSW','MEM'), ('PHI','DEN'), ('CHA','WAS'), ('MIA','ATL'), ('POR','NYK'), ('IND','BOS'), ('CLE','HOU'), ('TOR','LAC'), ('ORL','LAL'), ('BKN','CHA'), ('CHI','ATL'), ('MIN','UTA'), ('PHX','MEM'), ('MIL','NOP'), ('SAC','OKC'), ('GSW','NYK'), ('BOS','PHI'), ('SAS','CLE'), ('DET','DAL'), ('DEN','POR'), ('ORL','HOU'), ('PHI','NOP'), ('ATL','IND'), ('CHI','CHA'), ('MIN','LAC'), ('MIA','LAL'), ('MEM','MIL'), ('SAC','NYK'), ('UTA','GSW'), ('PHX','SAS'), ('TOR','BKN'), ('CHI','LAC'), ('MEM','WAS'), ('MIL','CLE'), ('DAL','MIA'), ('HOU','DET'), ('DEN','OKC'), ('NOP','ORL'), ('IND','CHA'), ('ATL','LAL'), ('BKN','PHI'), ('DEN','NYK'), ('GSW','SAC'), ('DET','WAS'), ('TOR','CLE'), ('OKC','CHI'), ('MIL','DAL'), ('MEM','MIA'), ('HOU','SAS'), ('PHX','POR'), ('IND','LAL'), ('CHA','SAC'), ('NYK','ATL'), ('NOP','BKN'), ('UTA','ORL'), ('LAC','PHX'), ('CLE','CHA'), ('WAS','CHI'), ('DET','TOR'), ('PHI','MIA'), ('OKC','MEM'), ('MIN','NOP'), ('DAL','BOS'), ('DEN','ORL'), ('POR','GSW'), ('ATL','UTA'), ('MIL','LAL'), ('SAS','BKN'), ('LAC','HOU'), ('CLE','MEM'), ('IND','SAC'), ('BOS','DET'), ('TOR','WAS'), ('PHI','DAL'), ('MIA','NYK'), ('OKC','PHX'), ('DEN','MIN'), ('POR','ORL'), ('GSW','NOP'), ('CHA','UTA'), ('BKN','ATL'), ('DET','CHI'), ('PHI','WAS'), ('NYK','MIL'), ('MEM','SAC'), ('SAS','LAC'), ('PHX','HOU'), ('POR','MIN'), ('TOR','DAL'), ('BOS','CHA'), ('MIL','IND'), ('OKC','LAC'), ('LAL','DEN'), ('CLE','ATL'), ('ORL','CHI'), ('DET','PHI'), ('IND','TOR'), ('NYK','WAS'), ('MIA','UTA'), ('MEM','SAS'), ('PHX','DEN'), ('SAC','HOU'), ('POR','NOP'), ('GSW','MIN'), ('TOR','BOS'), ('PHI','MIL'), ('GSW','HOU'), ('LAL','LAC'), ('DEN','NOP'), ('DET','WAS'), ('OKC','MEM'), ('BKN','NYK'), ('DAL','SAS'), ('SAC','MIN'), ('UTA','POR'), ('BOS','CLE'), ('CHA','OKC'), ('ORL','PHI'), ('ATL','MIL'), ('MIA','IND'), ('GSW','PHX'), ('DEN','MEM'), ('NOP','IND'), ('BOS','TOR'), ('CHI','ATL'), ('HOU','BKN'), ('MIN','CLE'), ('WAS','NYK'), ('MIA','PHI'), ('GSW','DAL'), ('SAS','DET'), ('MIL','ORL'), ('SAC','PHX'), ('POR','LAL'), ('LAC','UTA'), ('TOR','OKC'), ('MEM','CHA'), ('NOP','HOU'), ('DEN','SAC'), ('LAL','DAL'), ('ORL','ATL'), ('WAS','MIA'), ('MIN','BKN'), ('CHI','MIL'), ('UTA','DET'), ('POR','PHX'), ('CHA','BOS'), ('IND','PHI'), ('SAC','LAC'), ('TOR','CLE'), ('HOU','DEN'), ('SAS','GSW'), ('OKC','DAL'), ('WAS','ORL'), ('NYK','POR'), ('MIL','MIN'), ('LAL','PHX'), ('CLE','CHA'), ('IND','DEN'), ('MIA','TOR'), ('MIN','GSW'), ('CHI','UTA'), ('DAL','BKN'), ('SAS','OKC'), ('SAC','MEM'), ('LAC','DET'), ('BOS','ATL'), ('ORL','MIA'), ('WAS','POR'), ('HOU','PHI'), ('PHX','NYK'), ('LAL','NOP'), ('LAC','MEM'), ('BKN','TOR'), ('ORL','UTA'), ('ATL','IND'), ('CLE','OKC'), ('CHI','BOS'), ('WAS','DEN'), ('DAL','CHA'), ('GSW','DET'), ('MIL','SAS'), ('SAC','NOP'), ('LAC','NYK'), ('MIA','POR'), ('CLE','MIN'), ('PHX','MEM'), ('LAL','DET'), ('ORL','BKN'), ('WAS','BOS'), ('CHA','IND'), ('PHI','OKC'), ('ATL','DEN'), ('NOP','UTA'), ('DAL','CHI'), ('SAS','MIL'), ('SAC','GSW'), ('CLE','DET'), ('TOR','POR'), ('BKN','OKC'), ('MEM','MIN'), ('PHX','SAC'), ('LAL','NYK'), ('IND','MIA'), ('BOS','SAS'), ('CHA','TOR'), ('ORL','WAS'), ('DAL','DEN'), ('ATL','HOU'), ('NOP','CHI'), ('UTA','NYK'), ('GSW','MIL'), ('PHI','BOS'), ('DET','CLE'), ('MIN','POR'), ('OKC','HOU'), ('WAS','ATL'), ('BKN','MIA'), ('CHI','IND'), ('NYK','NOP'), ('MEM','SAS'), ('DAL','LAL'), ('UTA','CHA'), ('PHX','ORL'), ('SAC','MIL'), ('LAC','GSW'), ('HOU','MIN'), ('DET','CHI'), ('BOS','NOP'), ('OKC','LAL'), ('DAL','PHI'), ('DEN','CLE'), ('POR','MIL'), ('NYK','MIA'), ('WAS','UTA'), ('BKN','ATL'), ('MEM','GSW'), ('TOR','SAS'), ('PHX','CHA'), ('DEN','LAC'), ('DET','NOP'), ('IND','PHI'), ('BOS','CHI'), ('MIN','OKC'), ('POR','CHA'), ('SAC','ORL'), ('LAL','CLE'), ('ATL','PHX'), ('BKN','UTA'), ('MEM','HOU'), ('MIL','NYK'), ('LAC','CLE'), ('GSW','DAL'), ('PHI','BKN'), ('BOS','DET'), ('MIA','SAS'), ('MIN','IND'), ('OKC','TOR'), ('CHI','WAS'), ('DEN','CHA'), ('HOU','POR'), ('SAC','DAL'), ('LAL','ORL'), ('NYK','PHX'), ('MIL','BOS'), ('NOP','UTA'), ('GSW','DEN'), ('LAC','ORL'), ('PHI','CHI'), ('IND','MIN'), ('TOR','WAS'), ('MEM','CLE'), ('OKC','MIA'), ('SAS','ATL'), ('DAL','POR'), ('NOP','LAC'), ('BKN','MIL'), ('BOS','PHX'), ('ATL','DET'), ('NYK','PHI'), ('CHI','CLE'), ('MIN','TOR'), ('HOU','LAL'), ('GSW','ORL'), ('OKC','POR'), ('UTA','SAC'), ('SAS','MIA'), ('DEN','IND'), ('WAS','DET'), ('ATL','TOR'), ('BKN','PHI'), ('MIL','CHI'), ('MEM','NOP'), ('CLE','NYK'), ('HOU','OKC'), ('CHA','ORL'), ('MIA','SAC'), ('BOS','LAL'), ('MIN','DEN'), ('UTA','IND'), ('PHX','SAS'), ('POR','GSW'), ('DAL','LAC'), ('ORL','OKC'), ('DET','SAC'), ('ATL','LAC'), ('NYK','LAL'), ('BOS','MEM'), ('TOR','PHI'), ('MIA','WAS'), ('HOU','DEN'), ('CHI','MIN'), ('NOP','SAS'), ('PHX','IND'), ('GSW','UTA'), ('CLE','WAS'), ('BKN','LAL'), ('POR','DAL'), ('CHA','MIL'), ('ORL','BOS'), ('DET','MEM'), ('NYK','TOR'), ('OKC','ATL'), ('NOP','DEN'), ('MIN','HOU'), ('MIA','LAC'), ('CHI','SAC'), ('SAS','PHX'), ('GSW','IND'), ('UTA','DAL'), ('DET','BKN'), ('CLE','CHI'), ('MIN','OKC'), ('PHI','LAL'), ('DEN','HOU'), ('SAS','TOR'), ('NYK','BKN'), ('NOP','BOS'), ('ORL','LAC'), ('MEM','PHX'), ('ATL','WAS'), ('POR','IND'), ('DET','CLE'), ('MIA','ORL'), ('OKC','DAL'), ('MIN','SAC'), ('CHI','SAS'), ('UTA','HOU'), ('CHA','NYK'), ('TOR','ATL'), ('MIA','BOS'), ('PHI','GSW'), ('CLE','NOP'), ('MEM','DEN'), ('MIL','WAS'), ('DAL','PHX'), ('LAL','LAC'), ('IND','CHI'), ('BKN','DET'), ('NYK','MEM'), ('SAS','UTA'), ('POR','HOU'), ('SAC','OKC'), ('WAS','CHA'), ('CLE','TOR'), ('ATL','PHI'), ('BOS','GSW'), ('LAC','SAC'), ('DEN','UTA'), ('DET','TOR'), ('BKN','CHI'), ('HOU','DAL'), ('NOP','MEM'), ('MIL','DEN'), ('PHX','OKC'), ('LAL','POR'), ('LAC','MIN'), ('ORL','MIA'), ('IND','NYK'), ('WAS','BKN'), ('CLE','GSW'), ('DAL','ATL'), ('BOS','PHI'), ('SAS','CHA'), ('SAC','LAL'), ('POR','UTA'), ('DET','DEN'), ('HOU','NOP'), ('MIL','PHX'), ('TOR','CHI'), ('IND','DAL'), ('WAS','GSW'), ('CLE','NYK'), ('CHA','ORL'), ('ATL','BOS'), ('MIA','PHI'), ('BKN','PHX'), ('MEM','DET'), ('SAC','MIN'), ('LAC','SAS'), ('NOP','MIL'), ('HOU','CHA'), ('DEN','POR'), ('LAL','SAS'), ('DET','PHX'), ('BKN','GSW'), ('TOR','IND'), ('BOS','ORL'), ('MIN','ATL'), ('OKC','CLE'), ('DAL','MEM'), ('UTA','DEN'), ('LAC','MIA'), ('NYK','ORL'), ('CHI','NOP'), ('MIL','PHI'), ('POR','SAS'), ('LAL','HOU'), ('WAS','DAL'), ('PHI','MEM'), ('BOS','ATL'), ('OKC','DET'), ('IND','TOR'), ('PHX','HOU'), ('SAC','MIA'), ('UTA','POR'), ('ORL','MIL'), ('CHA','DAL'), ('DET','NYK'), ('TOR','BKN'), ('IND','NOP'), ('MIN','LAC'), ('GSW','LAL'), ('PHX','DEN'), ('SAC','SAS'), ('OKC','BOS'), ('PHI','CHI'), ('WAS','MEM'), ('ATL','NYK'), ('HOU','UTA'), ('CLE','LAC'), ('POR','MIA'), ('ORL','ATL'), ('IND','BKN'), ('DET','CHA'), ('TOR','MIN'), ('MIL','SAC'), ('DAL','UTA'), ('DEN','SAS'), ('GSW','MIA'), ('LAL','PHX'), ('WAS','CHI'), ('PHI','LAC'), ('NOP','POR'), ('OKC','SAS'), ('HOU','BOS'), ('CLE','ATL'), ('ORL','DET'), ('IND','MIL'), ('BKN','TOR'), ('NYK','WAS'), ('MIN','CHA'), ('MEM','POR'), ('DAL','SAC'), ('PHX','GSW'), ('UTA','MIA'), ('DEN','LAL'), ('BOS','LAC'), ('NOP','OKC'), ('DET','MIL'), ('ATL','MIA'), ('PHI','BKN'), ('CHI','CHA'), ('SAC','MEM'), ('GSW','HOU'), ('WAS','CLE'), ('ORL','DAL'), ('NYK','IND'), ('TOR','PHX'), ('MIN','BOS'), ('OKC','DEN'), ('UTA','SAS'), ('LAL','MEM'), ('POR','NOP'), ('LAC','SAC'), ('CHA','BKN'), ('ATL','DAL'), ('MIA','CLE'), ('CHI','PHX'), ('MIL','PHI'), ('UTA','HOU'), ('LAL','BOS'), ('TOR','IND'), ('DEN','MIN'), ('OKC','SAS'), ('CHI','WAS'), ('GSW','NOP'), ('POR','DET'), ('PHI','ATL'), ('CLE','MIA'), ('WAS','MIL'), ('BKN','ORL'), ('HOU','NYK'), ('DAL','MIN'), ('UTA','PHX'), ('LAC','MEM'), ('IND','CHA'), ('TOR','MIL'), ('CHI','OKC'), ('DEN','DET'), ('POR','BOS'), ('LAL','NOP'), ('GSW','SAC'), ('WAS','BKN'), ('CHA','NYK'), ('CLE','PHI'), ('SAS','DAL'), ('MIA','MIN'), ('ATL','ORL'), ('HOU','MEM'), ('PHX','LAC'), ('UTA','BOS'), ('PHI','NYK'), ('IND','POR'), ('OKC','SAC'), ('GSW','LAL'), ('ORL','MIN'), ('ATL','BKN'), ('TOR','CHA'), ('NOP','CLE'), ('MIA','DAL'), ('MIL','OKC'), ('MEM','SAC'), ('PHX','DET'), ('UTA','WAS'), ('LAC','DEN'), ('NYK','CHI'), ('MIA','BKN'), ('ATL','POR'), ('CLE','IND'), ('MEM','LAL'), ('BOS','HOU'), ('SAS','ORL'), ('PHX','GSW'), ('CHA','MIL'), ('MIN','DAL'), ('LAC','PHI'), ('SAC','DET'), ('DEN','TOR'), ('NOP','LAL'), ('GSW','WAS'), ('NYK','HOU'), ('ORL','POR'), ('CLE','UTA'), ('ATL','MEM'), ('MIA','MIL'), ('CHI','DAL'), ('SAS','IND'), ('CHA','SAS'), ('BOS','BKN'), ('OKC','LAC'), ('NOP','MIN'), ('DEN','GSW'), ('PHX','TOR'), ('LAL','PHI'), ('SAC','WAS'), ('CLE','BOS'), ('DET','OKC'), ('MIA','ORL'), ('BKN','MEM'), ('NYK','UTA'), ('MIN','CHI'), ('DAL','NOP'), ('MIL','IND'), ('POR','WAS'), ('CHA','DEN'), ('HOU','LAC'), ('SAC','PHI'), ('GSW','TOR'), ('WAS','ATL'), ('NYK','OKC'), ('BKN','SAS'), ('CHI','IND'), ('NOP','MIA'), ('MIN','ORL'), ('BOS','UTA'), ('DAL','MEM'), ('PHX','POR'), ('LAL','MIL'), ('CHA','HOU'), ('DET','UTA'), ('CLE','DEN'), ('MEM','ATL'), ('GSW','PHI'), ('POR','SAC'), ('BKN','CHI'), ('LAC','LAL'), ('MIN','NOP'), ('PHX','MIL'), ('BOS','OKC'), ('DAL','IND'), ('WAS','MIA'), ('HOU','ORL'), ('NYK','DET'), ('CLE','SAS'), ('SAC','TOR'), ('ATL','CHA'), ('DEN','MIL'), ('UTA','TOR'), ('IND','BOS'), ('WAS','NYK'), ('CHI','CLE'), ('SAS','DAL'), ('HOU','MIN'), ('MEM','ORL'), ('POR','PHX'), ('LAL','BKN'), ('GSW','LAC'), ('MIA','CHA'), ('PHI','DET'), ('ATL','NYK'), ('OKC','UTA'), ('DAL','DEN'), ('SAC','NOP'), ('ORL','CHI'), ('MIL','BOS'), ('POR','MEM'), ('GSW','BKN'), ('LAL','HOU'), ('CHA','CLE'), ('BOS','WAS'), ('OKC','MIN'), ('MIA','NYK'), ('SAS','DEN'), ('UTA','NOP'), ('LAC','BKN'), ('DAL','PHX'), ('ATL','CLE'), ('TOR','DET'), ('PHI','IND'), ('MIA','CHI'), ('MIL','GSW'), ('SAS','MIN'), ('UTA','MEM'), ('LAC','NOP'), ('POR','HOU'), ('ORL','CHA'), ('WAS','OKC'), ('CHI','BOS'), ('SAC','BKN'), ('LAL','DEN'), ('PHI','WAS'), ('NOP','ATL'), ('TOR','GSW'), ('MIL','MIA'), ('SAS','MEM'), ('UTA','LAL'), ('LAC','DAL'), ('DET','ORL'), ('NYK','CHA'), ('HOU','CLE'), ('MEM','OKC'), ('SAC','DAL'), ('POR','MIN'), ('PHI','TOR'), ('IND','GSW'), ('BOS','NYK'), ('ATL','OKC'), ('BKN','WAS'), ('CHI','MIA'), ('NOP','SAS'), ('DEN','LAC'), ('PHX','MIN'), ('LAL','UTA'), ('ORL','CLE'), ('CHA','PHI'), ('MIL','MEM'), ('HOU','SAC'), ('POR','DAL'), ('DET','GSW'), ('IND','MIA'), ('TOR','BOS'), ('ATL','WAS'), ('OKC','DEN'), ('SAS','CHI'), ('UTA','MIN'), ('LAC','PHX'), ('BKN','BOS'), ('PHI','ATL'), ('IND','CLE'), ('CHA','LAL'), ('ORL','SAC'), ('NYK','GSW'), ('HOU','CHI'), ('WAS','MIL'), ('MEM','NOP'), ('PHX','DAL'), ('TOR','DEN'), ('DET','LAL'), ('MIN','POR'), ('NOP','SAC'), ('SAS','UTA'), ('WAS','BOS'), ('NYK','LAC'), ('IND','PHX'), ('MIA','OKC'), ('BKN','ORL'), ('CHI','DEN'), ('MIL','DET'), ('DAL','HOU'), ('CHA','POR'), ('CLE','SAC'), ('TOR','LAL'), ('NOP','MEM'), ('MIN','PHI'), ('UTA','SAS'), ('ORL','IND'), ('BKN','LAC'), ('WAS','PHX'), ('DET','POR'), ('MIA','DEN'), ('NYK','TOR'), ('MEM','BOS'), ('MIL','HOU'), ('GSW','ATL'), ('CLE','LAL'), ('OKC','CHA'), ('CHI','PHI'), ('MIN','SAS'), ('DAL','UTA'), ('SAC','ATL'), ('ORL','BKN'), ('IND','HOU'), ('DET','LAC'), ('PHI','PHX'), ('BOS','POR'), ('NOP','NYK'), ('MIL','WAS'), ('DEN','SAS'), ('BKN','CLE'), ('CHA','LAC'), ('WAS','LAL'), ('CHI','NYK'), ('MIA','PHX'), ('MEM','TOR'), ('GSW','OKC'), ('UTA','ATL'), ('DAL','MIL'), ('DET','HOU'), ('BOS','MIN'), ('ORL','NOP'), ('PHI','POR'), ('GSW','SAS'), ('SAC','IND'), ('CHA','MIA'), ('CLE','PHX'), ('TOR','MEM'), ('BKN','POR'), ('MIN','LAL'), ('UTA','CHI'), ('DEN','OKC'), ('LAC','IND'), ('PHI','HOU'), ('ATL','NOP'), ('GSW','DEN'), ('SAC','SAS'), ('ORL','CHA'), ('WAS','NOP'), ('BKN','DET'), ('BOS','MIA'), ('MIN','DAL'), ('MEM','NYK'), ('OKC','PHX'), ('UTA','CLE'), ('MIL','TOR'), ('LAL','IND'), ('HOU','GSW'), ('SAC','LAC'), ('POR','UTA'), ('IND','BKN'), ('DET','MIA'), ('WAS','PHI'), ('ATL','CHA'), ('TOR','MIL'), ('NYK','MIN'), ('BOS','ORL'), ('MEM','DAL'), ('SAS','GSW'), ('DEN','CHI'), ('PHX','CLE'), ('LAC','OKC'), ('SAC','LAL'), ('CHA','ATL'), ('PHI','ORL'), ('BOS','MIL'), ('NYK','MIA'), ('IND','WAS'), ('PHX','CHI'), ('BKN','DAL'), ('DEN','UTA'), ('MIN','DET'), ('SAS','NOP'), ('HOU','TOR'), ('SAC','CLE'), ('POR','MEM'), ('LAL','OKC'), ('WAS','TOR'), ('ATL','DET'), ('MIA','IND'), ('PHI','MIL'), ('OKC','BKN'), ('NOP','CHA'), ('MIN','PHX'), ('DAL','HOU'), ('SAS','SAC'), ('DEN','MEM'), ('POR','CLE'), ('UTA','LAC'), ('LAL','CHI'), ('BOS','IND'), ('CHA','TOR'), ('NYK','ORL'), ('HOU','SAS'), ('LAC','CHI'), ('GSW','CLE'), ('MIA','DET'), ('MIL','BKN'), ('NOP','PHX'), ('MIN','SAC'), ('POR','DEN'), ('LAL','GSW'), ('ORL','BOS'), ('TOR','ATL'), ('OKC','NYK'), ('HOU','WAS'), ('SAS','PHI'), ('DAL','DET'), ('IND','ORL'), ('NOP','PHI'), ('CHA','WAS'), ('CLE','MIL'), ('CHI','BKN'), ('MIA','BOS'), ('MEM','OKC'), ('LAC','GSW'), ('DEN','SAC'), ('PHX','UTA'), ('SAS','HOU'), ('TOR','NYK'), ('MIL','ATL'), ('LAL','MIN'), ('CLE','BKN'), ('DET','BOS'), ('CHA','MIA'), ('IND','SAS'), ('CHI','ORL'), ('MEM','PHI'), ('HOU','PHX'), ('OKC','UTA'), ('NOP','WAS'), ('DEN','DAL'), ('LAC','MIN'), ('GSW','POR'), ('NYK','DET'), ('MIA','TOR'), ('UTA','DEN'), ('LAL','SAC'), ('PHI','CHA'), ('BOS','CHI'), ('ATL','CLE'), ('WAS','IND'), ('HOU','MEM'), ('BKN','MIL'), ('SAS','NOP'), ('MIN','NYK'), ('DAL','OKC'), ('ORL','TOR'), ('SAC','GSW'), ('POR','LAC'), ('PHX','LAL')]
|
|
# wantedEncounters = set(wantedGames)
|
|
# unwantedEncounters = [ (t1,t2) for t1 in shortnames for t2 in shortnames if not (t1,t2) in wantedEncounters ]
|
|
# # print ("unwanted ", unwantedEncounters)
|
|
|
|
# for (t1, t2) in wantedGames:
|
|
# gameCntr[(t1,t2)]+=1
|
|
|
|
# # for t1 in shortnames:
|
|
# # for t2 in shortnames:
|
|
# # print (gameCntr)
|
|
|
|
# playOnce = [ e for e in wantedEncounters if gameCntr[e] ==1]
|
|
# playTwice = [ e for e in wantedEncounters if gameCntr[e] ==2]
|
|
|
|
# t_cc = { t : [ c for c in confTeams.keys() if t in confTeams[c]] for t in teams }
|
|
# print (t_cc)
|
|
|
|
# interconferencegames = { (c1,c2) : 0 for c1 in confTeams.keys() for c2 in confTeams.keys() }
|
|
|
|
# for c in confTeams.keys():
|
|
# print (confTeams[c])
|
|
|
|
# for (tn1, tn2) in playTwice:
|
|
# print (teamByShort[tn1] , teamByShort[tn2])
|
|
# t1 = getTeamIdByName[teamByShort[tn1]]
|
|
# t2 = getTeamIdByName[teamByShort[tn2]]
|
|
# for c1 in t_cc[t1]:
|
|
# for c2 in t_cc[t2]:
|
|
# interconferencegames[(c1,c2)]+=2
|
|
|
|
|
|
# for (c1,c2) in interconferencegames.keys():
|
|
# print (confName[c1] , " - ", confName[c2], " : ", interconferencegames[(c1,c2)])
|
|
|
|
# # getTeamIdByName
|
|
# # print (playOnce)
|
|
# # print (playTwice)
|
|
|
|
|
|
# for t in teams:
|
|
# for c in clusters:
|
|
# # tripToClusterSaving[(t,c)]= cluster_distances[c,c] -2*distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c])
|
|
# print (cluster_distances[c,c], "-2*",distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c]) , cluster_distances[c,c] -2*distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c]) )
|
|
# print (" " , tripToClusterSaving[(t,c)] , tripToClusterSaving[t,c] )
|
|
|
|
# for t in teams:
|
|
# for c in clusters:
|
|
# print (getTeamById[t], " to ", c, " : " , cluster_distances[c,c] , "-2* " ,distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c]) , cluster_distances[c,c] -2.0*distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c]), cluster_distances[c,c] -2*distanceInKmByGPS(t_lon[t],t_lat[t], c_lon[c], c_lat[c]))
|
|
# for t2 in cluster_teams[c]:
|
|
# print ("--",getTeamById[t2])
|
|
# print ("---> " ,tripToClusterSaving[(t,c)])
|
|
|
|
|
|
|
|
# print (games)
|
|
# print (attractivity)
|
|
# for (t1,t2) in games:
|
|
# print (t1,t2)
|
|
# print (attractivity[t1,t2] )
|
|
gameAttractivity = { (t1,t2) : attractivity[t1,t2] for (t1,t2) in games if t1<t2 }
|
|
|
|
# print (gameAttractivity)
|
|
|
|
|
|
sorted_gameAttractivity = sorted(gameAttractivity.items(), key=operator.itemgetter(1))
|
|
# print ("ee " , sorted_gameAttractivity , " " , len (sorted_gameAttractivity))
|
|
|
|
nGames= len(games)
|
|
|
|
# print (range(int(0.8*0.5*nGames), int(0.5*nGames)) )
|
|
|
|
# for i in range(int(0.8*0.5*nGames), int(0.5*nGames)):
|
|
# print ( i, i in sorted_gameAttractivity.keys())
|
|
# print (nGames , len(sorted_gameAttractivity))
|
|
|
|
# print (range(int(0.6*0.5*nGames), int(0.5*nGames)))
|
|
|
|
# print (len(sorted_gameAttractivity) , int(0.5*nGames), range(int(0.8*0.5*nGames), min( len(sorted_gameAttractivity) , int(0.5*nGames)) ))
|
|
# print (len(sorted_gameAttractivity) , int(0.5*nGames), range(int(0.6*0.5*nGames), min( len(sorted_gameAttractivity) , int(0.5*nGames))))
|
|
topGames = [ sorted_gameAttractivity[i] for i in range(int(0.8*0.5*nGames), min( len(sorted_gameAttractivity) , int(0.5*nGames)) ) ]
|
|
goodGames = [ sorted_gameAttractivity[i] for i in range(int(0.6*0.5*nGames), min( len(sorted_gameAttractivity) , int(0.5*nGames))) ]
|
|
|
|
broadcastingwishes = BroadcastingWish.objects.filter(scenario=s2)
|
|
|
|
# nGames
|
|
|
|
|
|
# print (hawishes)
|
|
# print (objectiveFunctionWeights)
|
|
# print ("\n\n",roundObjects)
|
|
# for d in roundObjects:
|
|
# print (d)
|
|
|
|
# print (len(teams))
|
|
# for d in rounds:
|
|
# print (d)
|
|
|
|
# print (neighborPattern)
|
|
|
|
# x={}
|
|
# # #create a binary variable to state that a table setting is used
|
|
# for t1 in teams:
|
|
# for t2 in teams:
|
|
# for d in rounds:
|
|
# x[t1,t2,d] = pulp.LpVariable('x_'+t1+'_'+t2+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger)
|
|
|
|
# homePat= {(t1,d) : pulp.LpVariable('homePat_'+t1+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for d in rounds}
|
|
|
|
# prioVal ={'A': 25 , 'B': 5 , 'C': 1, 'Hard' : 1000}
|
|
|
|
# t_conference = {t : 0 for t in teams }
|
|
# for c in Conference.objects.filter(scenario=s2,regional=False).order_by('name'):
|
|
# print ("A" , c)
|
|
# cteams = c.teams.filter(active=True)
|
|
# for t in cteams:
|
|
# print ("group for ", t)
|
|
# if t_conference[t.id]!=0:
|
|
# print (getTeamById[t.id] , " in several groups")
|
|
# if t_conference[t.id]==0 or len(cteams)< len(t_conference[t.id].teams.filter(active=True)):
|
|
# t_conference[t.id]=c
|
|
# print (" is " , c )
|
|
# for t in set([t for t in teams if t_conference[t]==0 ]):
|
|
# print (" no group " , getTeamById[ t])
|
|
# return ''
|
|
|
|
|
|
nonBlocked = { (t,r) : len(getBasicDays[r]) for r in basicRounds for t in teams}
|
|
travelDays = { (t,r) : len(getBasicDays[r]) for r in basicRounds for t in teams}
|
|
hideDays = { (t,r) : len(getBasicDays[r]) for r in basicRounds for t in teams}
|
|
nonBlockedRounds = { (t,r) : len(getDays[r]) for r in rounds for t in teams}
|
|
travelRounds = { (t,r) : len(getDays[r]) for r in rounds for t in teams}
|
|
hideRounds = { (t,r) : len(getDays[r]) for r in rounds for t in teams}
|
|
|
|
for bl in blockings:
|
|
bl_val =1.0 if bl['time']=="----" else 0.5
|
|
# if bl['time']!="----":
|
|
# print (bl, bl_val , getDayById[bl['day_id']] ,getDayById[bl['day_id']]['round'] ,getDayById[bl['day_id']]['round'] !=0 )
|
|
if getDayById[bl['day_id']]['round'] !=0:
|
|
if bl['type'] in ["Home","Hide"]:
|
|
nonBlocked[( bl['team_id'], getBasicRound[getDayById[bl['day_id']]['round']])]-=bl_val
|
|
nonBlockedRounds[( bl['team_id'], getDayById[bl['day_id']]['round'])]-=bl_val
|
|
# print ('FOUND HOME BLOCKING ', bl)
|
|
if bl['type'] in ["Away","Hide"]:
|
|
travelDays[( bl['team_id'], getBasicRound[getDayById[bl['day_id']]['round']])]-=bl_val
|
|
travelRounds[( bl['team_id'], getDayById[bl['day_id']]['round'])]-=bl_val
|
|
# print ('FOUND AWAY BLOCKING ', bl)
|
|
if bl['type'] in ["Hide"]:
|
|
hideDays[( bl['team_id'], getBasicRound[getDayById[bl['day_id']]['round']])]-=bl_val
|
|
hideRounds[( bl['team_id'], getDayById[bl['day_id']]['round'])]-=bl_val
|
|
# print ('FOUND AWAY BLOCKING ', bl)
|
|
|
|
noPlayRounds = { t: [ r for r in rounds if nonBlockedRounds[(t,r)] + travelRounds[(t,r)]==0 ] for t in teams }
|
|
noHomeRounds = { t: [ r for r in rounds if nonBlockedRounds[(t,r)] ==0 ] for t in teams }
|
|
# print("nonBlockedRounds" ,nonBlockedRounds)
|
|
# print("noHomeRounds" ,noHomeRounds)
|
|
# print("noPlayRounds" ,noPlayRounds)
|
|
|
|
playRounds = { t: sorted([ r for r in rounds if hideRounds[(t,r)]>0 ]) for t in teams }
|
|
|
|
|
|
# scale blocking of basic round to [0,1]
|
|
for t in teams:
|
|
for r in basicRounds:
|
|
if len(getBasicDays[r])>0:
|
|
nonBlocked[(t,r)]/=len(getBasicDays[r])
|
|
travelDays[(t,r)]/=len(getBasicDays[r])
|
|
if getTeamById[t]=="AX Armani Exchange Milan":
|
|
print (r , getRealRounds[r] , nonBlocked[(t,r)] , nonBlocked[(t,r)] )
|
|
|
|
for t in teams:
|
|
if mathModelName=="UEFA NL" and noPlayRounds[t] in [ [3,4] ]:
|
|
t_usePhases[t]= False
|
|
print ("No need for phases " , getTeamById[t])
|
|
for t2 in opponents[t]:
|
|
t_usePhases[t2]= False
|
|
print (" -- also no need for phases " , getTeamById[t2])
|
|
if getTeamById[t]=="AX Armani Exchange Milan":
|
|
t_usePhases[t]= False
|
|
print ("setting t_usePhases of ", getTeamById[t],t_usePhases[t] )
|
|
|
|
runPatternAssignmentFirst=False
|
|
|
|
if runMode=='New' and optSteps[0][0]=='HEURISTIC' and not thisSeason.useFeatureOpponentMatrix and not thisSeason.groupBased and len(fixedGames)+len(fixedGames2)==0 :
|
|
runPatternAssignmentFirst=True
|
|
|
|
chosenGames = [ ]
|
|
|
|
useFullModel1= False
|
|
|
|
usePatterns= not mathModelName in ["NHL", "LNR"]
|
|
usePatterns= not mathModelName in ["NHL"]
|
|
|
|
|
|
balanceBreaks = mathModelName=="LNR"
|
|
haSymmetric = not mathModelName in ["NHL" , "LNR"]
|
|
haSymmetric = not mathModelName in ["NHL", "Ligue 1", "Costa Rica Premier League"]
|
|
haSymmetric = not mathModelName in ["NHL"]
|
|
# haSymmetric = not mathModelName in ["NHL" , "LNR"]
|
|
if thisSeason.symmetry:
|
|
haSymmetric=True
|
|
|
|
use2BreakPatterns = False
|
|
|
|
# if thisSeason.initBreaks>=2 and objectivePrio != 'Trips' :
|
|
if thisSeason.initBreaks>=2 :
|
|
use2BreakPatterns = True
|
|
# use2BreakPatterns = False
|
|
|
|
# if objectivePrio == 'Trips' and not regionalPatternUse:
|
|
# use2BreakPatterns = False
|
|
|
|
|
|
|
|
# basicRounds= range(1,40)
|
|
# half_symmetry_offset = 1 if mathModelName in [ "TOP 14"] else 0
|
|
half_symmetry_offset = 0 if thisSeason.symmetry or use2BreakPatterns or not thisSeason.startWithBreakAllowed or not thisSeason.endWithBreakAllowed else 1
|
|
|
|
# if mathModelName in [ "Ligue 1"]:
|
|
# half_symmetry_offset = 4
|
|
|
|
# print (half_symmetry_offset , thisSeason.symmetry , use2BreakPatterns)
|
|
|
|
|
|
prev_mirror_round= { r : 0 if r<=nRounds1 else r-nRounds1+half_symmetry_offset for r in basicRounds }
|
|
|
|
|
|
# for r in basicRounds:
|
|
# print (r, " --> " , prev_mirror_round[r] )
|
|
# print ("")
|
|
|
|
|
|
for r in basicRounds:
|
|
if r>nRounds1 and int((r-1)/nRounds1) == int((prev_mirror_round[r]-1)/nRounds1):
|
|
# prev_mirror_round[r]-=nRounds1
|
|
prev_mirror_round[r] = int((r-1)/nRounds1-1)*nRounds1 +half_symmetry_offset+1-prev_mirror_round[r]%nRounds1
|
|
|
|
if mathModelName in [ "LNR"] and False:
|
|
prev_mirror_round[14]=4
|
|
prev_mirror_round[15]=3
|
|
prev_mirror_round[16]=2
|
|
prev_mirror_round[17]=1
|
|
prev_mirror_round[18]=13
|
|
prev_mirror_round[19]=12
|
|
prev_mirror_round[20]=11
|
|
prev_mirror_round[21]=10
|
|
|
|
prev_mirror_round[22]=9
|
|
prev_mirror_round[23]=8
|
|
prev_mirror_round[24]=7
|
|
prev_mirror_round[25]=6
|
|
prev_mirror_round[26]=5
|
|
|
|
|
|
# for r in basicRounds:
|
|
# print (r, " --> " , prev_mirror_round[r] )
|
|
|
|
|
|
|
|
|
|
|
|
getPhaseOfBasicRound={ br : getPhaseOfRound[getRealRounds[br][0]] for br in basicRounds}
|
|
getBasicRoundsOfPhase={ ph : [ br for br in basicRounds if getPhaseOfBasicRound[br]==ph ] for ph in phases }
|
|
|
|
# print (getPhaseOfBasicRound)
|
|
# print (getBasicRoundsOfPhase)
|
|
|
|
|
|
if use2BreakPatterns or nTeams >200 or not usePatterns or thisSeason.minRoundsBetweenGameOfSameTeams>0 :
|
|
useFullModel1=True
|
|
useFullModel1=True
|
|
|
|
|
|
preplan_phases = phases
|
|
preplan_phases= [0]
|
|
if not haSymmetric:
|
|
preplan_phases = phases
|
|
|
|
fixedGamesRounds=[]
|
|
|
|
starweight={t : 0.0 for t in teams}
|
|
for t1 in teams :
|
|
for t2 in teams :
|
|
starweight[t1]+=distance[getTeamById[t1],getTeamById[t2]]
|
|
|
|
# if thisSeason.minBreaks or len(fixedGames)==0:
|
|
|
|
available_days={ (t,d) : 1 for t in teams for d in days}
|
|
|
|
# for c in Conference.objects.filter(scenario=s2, name="Eastern Conference"):
|
|
# for t in c.teams.all():
|
|
# for r in rounds:
|
|
# available_days[t.id,earliestDay[r]] =0
|
|
|
|
# for c in Conference.objects.filter(scenario=s2, name="Western Conference"):
|
|
# for t in c.teams.all():
|
|
# for r in rounds:
|
|
# available_days[t.id,latestDay[r]] =0
|
|
|
|
for bl in blockings:
|
|
if bl['type'] in ["Home","Hide"] and bl['time']=='----':
|
|
available_days[ bl['team_id'],bl['day_id']] =0
|
|
|
|
t_blocked_at={ (t,r) : sum([available_days[t,d] for d in getDays[r]])==0 for t in teams for r in rounds}
|
|
|
|
if runPatternAssignmentFirst:
|
|
|
|
debug= True
|
|
debug= False
|
|
comptime = 500
|
|
gap = 0.05
|
|
if debug:
|
|
comptime = 30
|
|
gap = 0.5
|
|
|
|
possGames = optimize_model1(comptime,gap)
|
|
print (possGames)
|
|
print (len(possGames))
|
|
chosenGames, unChosenGames = optimize_model4(possGames)
|
|
|
|
print (len(chosenGames) , " chosen games" , chosenGames )
|
|
print (len(unChosenGames) , "unchosen games : ", unChosenGames)
|
|
|
|
# exit(0)
|
|
# print (len(chosenGames))
|
|
|
|
fineDistributionModel4 = False
|
|
fineDistributionModel4 = nBasicTeams<nTeams and thisSeason.useFeatureOpponentMatrix and mathModelName=="NBA"
|
|
|
|
if fineDistributionModel4:
|
|
fixedGamesRounds= optimize_model4_fine(chosenGames)
|
|
|
|
|
|
# print (r, ' ' , parse(getNiceDay[earliestDay[r]]), ' ',parse(getNiceDay[latestDay[r]]))
|
|
|
|
|
|
|
|
# print ('\n')
|
|
# for p in phases:
|
|
# for d in getDaysOfPhase[p] :
|
|
# print (p,d, getRoundDaysByDay[d])
|
|
|
|
# return ''
|
|
|
|
|
|
displayGroups ={}
|
|
|
|
if thisSeason.groupBased:
|
|
for c in set([t_conference[t] for t in teams if t_conference[t]!=0 ]):
|
|
print ("B" , c)
|
|
cteams = c.teams.filter(active=True)
|
|
displayGroups[c.name] = [t.id for t in cteams.order_by('name')]
|
|
else:
|
|
displayGroups['All'] = realteams
|
|
|
|
|
|
# thisCountry =""
|
|
# for t in realteams:
|
|
# thisCountry=t_country[t]
|
|
# # print (getTeamById[t], t_country[t] , t_conference[t])
|
|
# # print (thisCountry)
|
|
# print ("bt",len(bad_travels))
|
|
|
|
# if thisCountry=="United States":
|
|
|
|
# print (thisCountry)
|
|
# return ""
|
|
|
|
|
|
|
|
# for d in displayGroups.keys():
|
|
# print (d, displayGroups[d])
|
|
# return ''
|
|
|
|
finalRoundDays=getRoundDaysByRound[nRounds].copy()
|
|
if mathModelName=="Champions Hockey League" and True:
|
|
finalRoundDays+=getRoundDaysByRound[nRounds-1]
|
|
|
|
|
|
# print (finalRoundDays)
|
|
# return ''
|
|
# lastRoundSync = models.BooleanField(default=False, verbose_name="Synchronize games of last round")
|
|
|
|
model2 = pulp.LpProblem("League_Scheduling_Model_--_Schedule_Games_"+str(thisScenario.id), pulp.LpMinimize)
|
|
|
|
def makeIntVar(v):
|
|
if type(v) != int :
|
|
v.cat=pulp.LpInteger
|
|
# print ("int var ", v)
|
|
|
|
def setStart(v,vl):
|
|
if type(v) != int :
|
|
vl=float(vl)
|
|
v.start = vl
|
|
|
|
def setLB(v,vl):
|
|
if type(v) != int :
|
|
vl=float(vl)
|
|
v.lowBound = vl
|
|
# print ("set lb ", v , " = ", vl)
|
|
|
|
|
|
def setUB(v,vl):
|
|
if type(v) != int :
|
|
vl=float(vl)
|
|
v.upBound = vl
|
|
# print ("set ub ", v , " = ", vl)
|
|
|
|
def getVal(v):
|
|
if type(v) == int :
|
|
return v
|
|
else:
|
|
return v.value()
|
|
|
|
nextDay = { d : -1 for d in days+higherLeagueDayIds }
|
|
previousDay = { d : -1 for d in days+higherLeagueDayIds}
|
|
|
|
# cntr=0
|
|
lastDay=parse("01.01.1990")
|
|
for thisDay in sorted(getDayByDateTime.keys()):
|
|
if thisDay-lastDay==datetime.timedelta(days=1):
|
|
# cntr+=1
|
|
d1 = getDayByDateTime[lastDay]
|
|
d2 = getDayByDateTime[thisDay]
|
|
nextDay[d1]=d2
|
|
previousDay[d2]=d1
|
|
# print ("next day of " , getNiceDay[d1] , ' ' , getNiceDay[d2])
|
|
lastDay=thisDay
|
|
|
|
# print (cntr)
|
|
# cntr=0
|
|
# for d in days+higherLeagueDayIds :
|
|
# for d2 in days+higherLeagueDayIds:
|
|
# if getDateTimeDay[d2]-getDateTimeDay[d]==datetime.timedelta(days=1):
|
|
# cntr+=1
|
|
# nextDay[d]=d2
|
|
# previousDay[d2]=d
|
|
# print ("next day of " , getNiceDay[d] , ' ' , getNiceDay[d2])
|
|
# print (cntr)
|
|
|
|
|
|
cntr= 0
|
|
cntr2= 0
|
|
|
|
# print ("games",games)
|
|
# print (roundDays)
|
|
|
|
seedTV = []
|
|
dontPlay = []
|
|
dontPlayGames = []
|
|
|
|
for bl in blockings:
|
|
if bl['type']=="Hide":
|
|
dontPlay += [(bl['team_id'],bl['day_id']) ]
|
|
|
|
dontPlay += [(t,d) for d in days for t in teams if getDayMaxGames[d]==0 ]
|
|
|
|
# for t1 in teams:
|
|
# for d in days:
|
|
# if blocked_arena[(t1,d, "----" )] :
|
|
# dontPlayGames += [(t1,t2,d) for t2 in teams]
|
|
|
|
|
|
# print()
|
|
# print(len(dontPlayGames) , " ", len (days)*len(teams)*(len(teams)-1))
|
|
|
|
|
|
if mathModelName=="NBA":
|
|
for t1 in teams:
|
|
for d in days:
|
|
if blocked_arena[(t1,d, "----" )] :
|
|
dontPlayGames += [(t1,t2,d) for t2 in teams]
|
|
# print (len(dontPlayGames), "BLOKING " )
|
|
|
|
for enc in encwishes:
|
|
# print ("ENC " ,enc , enc['reason'][:11],enc['reason'][:11]== 'TV Network:')
|
|
if enc['reason'][:11]== 'TV Network:':
|
|
print ("ENC " , encGames[enc['id']] ,encDays[enc['id']] )
|
|
seedTV += [ (t1,t2,d,enc['reason'][12:]) for (t1,t2) in encGames[enc['id']] for d in encDays[enc['id']]]
|
|
if enc['maxGames']== 0 and not enc['time'] in [getIdByTime["Early"], getIdByTime["Late"]]:
|
|
dontPlayGames += [ (t1,t2,d) for (t1,t2) in encGames[enc['id']] for d in encDays[enc['id']]]
|
|
|
|
# print (len(dontPlayGames),encGames[enc['id']] , encDays[enc['id']] , enc['reason'] )
|
|
|
|
|
|
usingRDs={t: [] for t in teams}
|
|
for (t1,t2,d,channel) in seedTV:
|
|
# print (t1,t2,d , gameCntr[(t1,t2)], gameCntr[(t1,t2)]==1)
|
|
usingRDs[t1]+=getRoundDaysByDay[d]
|
|
usingRDs[t2]+=getRoundDaysByDay[d]
|
|
for d2 in [ previousDay[d], nextDay[d]]:
|
|
if channel=="ABC" and d2!=-1:
|
|
dontPlay+=[(t1,d2), (t2,d2)]
|
|
|
|
TVteams = [t for t in teams if len (usingRDs[t])>=10 ]
|
|
|
|
# for t in teams:
|
|
# print (t, getTeamById[t], [ r for (r,d) in usingRDs[t]], t_conference[t])
|
|
|
|
# print (TVteams)
|
|
# print ("CHECKPOINT ", 5)
|
|
|
|
# print (seedTV)
|
|
# print (dontPlay)
|
|
|
|
x= {(t1,t2,rd) : 0 for t1 in teams for t2 in teams for rd in roundDays}
|
|
for (t1,t2) in games:
|
|
for rd in roundDays:
|
|
x[(t1,t2,rd)]=1
|
|
|
|
for (t1,t2,rd) in x.keys():
|
|
if blocked_arena[(t1,rd[1],"----")] and runMode=='Improve' and not thisSeason.allowBlockingViosInImprove:
|
|
# cntr +=1
|
|
# print ("FORBIDDING")
|
|
|
|
x[(t1,t2,rd)]=0
|
|
|
|
for (t1,t2,d,channel) in seedTV:
|
|
if gameCntr[(t1,t2)]==1:
|
|
for (r,d2) in roundDays:
|
|
if d != d2 :
|
|
# cntr +=1
|
|
x[(t1,t2,(r,d2))]=0
|
|
|
|
for t3 in teams:
|
|
if not t3 in [t1,t2]:
|
|
for rd in getRoundDaysByDay[d]:
|
|
x[(t1,t3,rd)]=0
|
|
x[(t2,t3,rd)]=0
|
|
x[(t3,t1,rd)]=0
|
|
x[(t3,t2,rd)]=0
|
|
# cntr +=4
|
|
|
|
for (t,d) in dontPlay:
|
|
for t3 in teams:
|
|
if not t3 in [t1,t2]:
|
|
for rd in getRoundDaysByDay[d]:
|
|
x[(t,t3,rd)]=0
|
|
x[(t3,t,rd)]=0
|
|
|
|
for (t1,t2,d) in dontPlayGames:
|
|
for rd in getRoundDaysByDay[d]:
|
|
x[(t1,t2,rd)]=0
|
|
|
|
attendance = { (t1,t2,d) : 0 for (t1,t2) in games for d in days }
|
|
if thisSeason.useFeaturePrediction:
|
|
# learner = AttendanceLearner(thisSeason.id)
|
|
# attendance = learner.predict_games(attendance.keys())
|
|
oldestTrainingGame= parse("2015-01-01")
|
|
oldestTrainingGame=oldestTrainingGame.date()
|
|
games_train = Game.objects.filter(season=thisSeason).exclude(historic_season=None)
|
|
print ( " all games",len(games_train), )
|
|
games_train = [g for g in games_train if g.date>oldestTrainingGame ]
|
|
print ( " important games",len(games_train), )
|
|
|
|
games_predict = attendance.keys()
|
|
|
|
X= []
|
|
y =[]
|
|
homeAttendances = {t: [] for t in teams+inactive_teams}
|
|
for game in games_train:
|
|
if game.attendance>0:
|
|
homeAttendances[game.homeTeam.id].append(game.attendance)
|
|
for t in teams+inactive_teams:
|
|
homeAttendances[t]=sorted(homeAttendances[t])
|
|
# print (getTeamById[t], homeAttendances[t])
|
|
if len(homeAttendances[t])==0:
|
|
homeAttendances[t]=[7500]
|
|
maxAttendance = {t: homeAttendances[t][-1] for t in teams+inactive_teams }
|
|
# maxAttendance = {t: homeAttendances[t][int(0.9*(len(homeAttendances[t])))] for t in teams+inactive_teams }
|
|
medianAttendance = {t: homeAttendances[t][int(0.5*(len(homeAttendances[t])))] for t in teams+inactive_teams }
|
|
loyalty = {t: medianAttendance[t]/maxAttendance[t] for t in teams+inactive_teams }
|
|
|
|
for t in teams+inactive_teams:
|
|
print (getTeamById[t], loyalty[t] , medianAttendance[t] , maxAttendance[t] , )
|
|
|
|
def getFeatureVector(t1,t2,d):
|
|
ds = distanceInKmByGPS(t_lon[t1],t_lat[t1], t_lon[t2], t_lat[t2])
|
|
# print ( d.day , d.month , d.year , " -> " , (d.month+5)%12 , " -> " , int((d.month+4)%12/2) , d.month==12 and d.day >15 , d.weekday() , d.weekday() in [4,5,6])
|
|
# print ( d.year," -> " , d.year-2015 )
|
|
gm={
|
|
# 'homeTeam_id': t1, 'awayTeam_id': t2,
|
|
# 'month': d.month,
|
|
'year': d.year-2015 ,
|
|
'month': int((d.month+4)%12/2) ,
|
|
'weekday': d.weekday() ,
|
|
'weekend': d.weekday() in [4,5,6],
|
|
'holiday': d.month==12 and d.day >15 ,
|
|
'summer': d.month in [6,7,8,9],
|
|
'winter': d.month in [12,1,2],
|
|
'home_attractivity': t_attractivity[t1], 'away_attractivity': t_attractivity[t2],
|
|
'attractivity_ratio': t_attractivity[t2]/max(1,t_attractivity[t1]),
|
|
'home_lat': t_lat[t1] , 'home_lon': t_lon[t1] ,
|
|
'away_lat': t_lat[t2], 'away_lon': t_lon[t2],
|
|
'distance' : ds ,
|
|
'distance_frac' : ds/medianAttendance[t2] ,
|
|
'loyalty_home' : loyalty[t1] ,
|
|
'medianAttendance_home' : 0.001*medianAttendance[t1] ,
|
|
'maxAttendance_home' : 0.001*maxAttendance[t1] ,
|
|
# 'medianAttendance_away' : 0.001*medianAttendance[t2] ,
|
|
# 'maxAttendance_away' : 0.001*maxAttendance[t2] ,
|
|
}
|
|
for t in teams+inactive_teams:
|
|
if t1 == t:
|
|
gm["home_"+str(t1)]=True
|
|
if t2 == t:
|
|
gm["away_"+str(t2)]=False
|
|
for c in countries:
|
|
if t_country[t1] == c:
|
|
gm["home_country_"+str(t1)]=True
|
|
if t_country[t2] == c:
|
|
gm["away_country_"+str(t2)]=False
|
|
return list(gm.values())
|
|
|
|
for game in games_train:
|
|
X.append(getFeatureVector(game.homeTeam.id, game.awayTeam.id,game.date) )
|
|
y.append(game.attendance)
|
|
|
|
X_train, X_test, y_train, y_test = train_test_split(
|
|
X, y, test_size=0.2, random_state=1)
|
|
|
|
rf_regressor = RandomForestRegressor(n_estimators = 200 , random_state = 42)
|
|
# score on training 0.959517674767985
|
|
# score on test 0.8494965525219991
|
|
# rf_regressor = GradientBoostingRegressor(n_estimators = 200 , random_state = 42)
|
|
# score on training 0.9022637786547619
|
|
# score on test 0.8047414718789097
|
|
rf_regressor.fit(X_train,y_train)
|
|
score = rf_regressor.score(X_train,y_train)
|
|
print ("score on training " , score)
|
|
score = rf_regressor.score(X_test,y_test)
|
|
print ("score on test " , score)
|
|
|
|
X= []
|
|
y =[]
|
|
for (t1,t2,d) in attendance.keys():
|
|
X.append(getFeatureVector(t1,t2,getDateTimeDay[d]) )
|
|
|
|
attendance = dict(zip(games_predict,rf_regressor.predict(X)))
|
|
|
|
for g in games_predict:
|
|
# print (g, int (attendance[g]) , maxAttendance[g[0]], int (attendance[g]) < maxAttendance[g[0]], min ( int (attendance[g]) , maxAttendance[g[0]]))
|
|
attendance[g] = min ( int (attendance[g]) , maxAttendance[g[0]])
|
|
|
|
# print ( sum (x[ttrd] for ttrd in x.keys()) , len(games)*len(roundDays))
|
|
|
|
# x= {(t1,t2,rd) : 0 for t1 in teams for t2 in teams for rd in roundDays}
|
|
x_round= {(t1,t2,r) : 0 for t1 in teams for t2 in teams for r in rounds}
|
|
x_time= {(t1,t2,rd,tm) : 0 for t1 in teams for t2 in teams for rd in roundDays for tm in times}
|
|
if evalRun:
|
|
x= {(t1,t2,rd) : 0 for t1 in teams for t2 in teams for rd in roundDays}
|
|
for (t1,t2,r,d) in currentSolution:
|
|
x[(t1,t2,(r,d))]=1
|
|
if currentKickoffTimes[(t1,t2,d)] in times:
|
|
x_time[(t1, t2, (r, d), currentKickoffTimes[(t1,t2,d)])]=1
|
|
# print ("setting " , t1,t2,r,d,currentKickoffTimes[(t1,t2,d)])
|
|
|
|
for (t1,t2) in games:
|
|
for rd in roundDays:
|
|
# print ("make var " ,t1,t2,rd)
|
|
if x[(t1,t2,rd)]==1 :
|
|
# if not blocked_arena[(t1,rd[1],"----")] or runMode=='New':
|
|
if not evalRun:
|
|
x[(t1,t2,rd)] = pulp.LpVariable('x_'+str(t1)+'_'+str(t2)+'_'+str(rd[0])+'_'+str(rd[1]), lowBound = 0, upBound = 1, cat = pulp.LpContinuous)
|
|
cntr +=1
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
x_time[(t1,t2,rd,tm)] = pulp.LpVariable('x_'+str(t1)+'_'+str(t2)+'_'+str(rd[0])+'_'+str(rd[1])+'_'+tm , lowBound = 0, upBound = 1, cat = pulp.LpContinuous)
|
|
else:
|
|
cntr+=len(roundDays)
|
|
|
|
for r in rounds:
|
|
x_round[(t1,t2,r)]= pulp.LpVariable('x_round_'+str(t1)+'_'+str(t2)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous)
|
|
model2+= x_round[(t1,t2,r)] == sum([x[(t1,t2,rd)] for rd in getRoundDaysByRound[r]])
|
|
|
|
|
|
t_prev_mirror_round ={(t,r) : 0 for t in teams for r in rounds}
|
|
|
|
for t1 in teams:
|
|
phaseLength= int(len(playRounds[t1])/nPhases+0.5)
|
|
# print ("phaseLength", phaseLength)
|
|
for i in range(len(playRounds[t1])):
|
|
# print (i, phaseLength)
|
|
if i >=phaseLength:
|
|
# print ("setting " , playRounds[t1], playRounds[t1][i-phaseLength])
|
|
# print ("setting " , playRounds[t1][i], "->",playRounds[t1][i-phaseLength])
|
|
t_prev_mirror_round[(t1,playRounds[t1][i])]=playRounds[t1][i-phaseLength]
|
|
# t_prev_mirror_round[(t,playRounds[t1][i])]=5
|
|
|
|
|
|
# for tr in t_prev_mirror_round.keys():
|
|
# print( "t_prev_mirror_round " ,tr , t_prev_mirror_round[tr])
|
|
|
|
# print (prev_mirror_round)
|
|
|
|
|
|
if not evalRun:
|
|
for (t1,t2) in games:
|
|
for r in rounds:
|
|
if r > nRounds1 and thisSeason.symmetry :
|
|
prev_round =prev_mirror_round[r]
|
|
if thisSeason.groupBased and len(noPlayRounds[t1])>0 and noPlayRounds[t1]==noPlayRounds[t2]:
|
|
prev_round=t_prev_mirror_round[t1,r]
|
|
|
|
if prev_round>0:
|
|
model2+= x_round[(t1,t2,r)] == x_round[(t2,t1,prev_round)]
|
|
# print ("x_round[(",t1,",",t2,",",r,")] == x_round[(",t2,t1,prev_mirror_round[r],")]")
|
|
# print ( t1,t2,r , " -> ",prev_mirror_round[r])
|
|
|
|
|
|
# for (t1,t2) in games:
|
|
# # every pair plays each other in each phase once
|
|
# for p in phases:
|
|
# if p<len(phases)-1 or True: # phase violation in last phase possible if it contained more rounds than necessary
|
|
# if t_usePhases[t1] or t_usePhases[t2]:
|
|
# if thisSeason.groupBased and len(noPlayRounds[t1])>0 and noPlayRounds[t1]==noPlayRounds[t2]:
|
|
# relDays = []
|
|
# phaseLength= int(len(playRounds[t1])/nPhases+0.5)
|
|
# for rr in playRounds[t1][p*phaseLength:(p+1)*phaseLength]:
|
|
# relDays+=getDays[rr]
|
|
# print ("adding days of round ", rr , " to phase ", p)
|
|
# print ("reldays", relDays)
|
|
# else:
|
|
# relDays = getDaysOfPhase[p]
|
|
# model2 += lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for d in relDays for rd in getRoundDaysByDay[d] ] ) <= 1
|
|
|
|
|
|
|
|
# for r in rounds:
|
|
# if r > nRounds1 and (thisSeason.symmetry or haSymmetric):
|
|
# print ( r , " -> ",prev_mirror_round[r])
|
|
# print (len(games))
|
|
|
|
|
|
|
|
|
|
for (t1,t2,(r,d)) in x.keys():
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times :
|
|
if blocked_arena[(t1,d,tm)] and runMode=='Improve':
|
|
x_time[(t1,t2,(r,d), tm)]=0
|
|
# print ("forbidding tm ", t1,t2,r,d, tm)
|
|
cntr2+=1
|
|
# print ("FORBIDDING")
|
|
|
|
|
|
print (" .... got rid of " , len(x.keys())-cntr, " + " ,cntr2, " vars")
|
|
|
|
|
|
|
|
|
|
for (t1,t2,d,channel) in seedTV:
|
|
print (t1,t2,d , gameCntr[(t1,t2)], gameCntr[(t1,t2)]==1)
|
|
model2+= sum([x[(t1,t2,rd)] for rd in getRoundDaysByDay[d] ])==1
|
|
|
|
# model2+= lpSum( x[rr] for rr in x.keys() )
|
|
# model2.solve(XPRESS(msg=1,maxSeconds = 25, keepFiles=True))
|
|
# return ""
|
|
|
|
if thisSeason.lastRoundSync:
|
|
if thisSeason.useFeatureKickOffTime:
|
|
lastRoundPlayed= {(g,rd,tm1) : pulp.LpVariable('x_'+str(g)+'_'+str(rd[1])+'_'+tm1 , lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for g in displayGroups.keys() for rd in finalRoundDays for tm1 in times}
|
|
else:
|
|
lastRoundPlayed= {(g,rd) : pulp.LpVariable('x_'+str(g)+'_'+str(rd[1]) , lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for g in displayGroups.keys() for rd in finalRoundDays }
|
|
homeInRound= {(t1,r) : pulp.LpVariable('homeInRound_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for r in rounds}
|
|
awayInRound= {(t1,r) : pulp.LpVariable('awayInRound_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for r in rounds}
|
|
gameInBasicRound= {(t1,t2,r) : pulp.LpVariable('gameInBasicRound_'+str(t1)+'_'+str(t2)+'_'+str(r), lowBound = 0, upBound = defaultGameRepetions, cat = pulp.LpContinuous) for (t1,t2) in games for r in basicRounds}
|
|
homeInBasicRound= {(t1,r) : pulp.LpVariable('homeInBasicRound_'+str(t1)+'_'+str(r), lowBound = 0, cat = pulp.LpContinuous) for t1 in teams for r in basicRounds}
|
|
awayInBasicRound= {(t1,r) : pulp.LpVariable('awayInBasicRound_'+str(t1)+'_'+str(r), lowBound = 0, cat = pulp.LpContinuous) for t1 in teams for r in basicRounds}
|
|
break3InRound= {(t1,r) : pulp.LpVariable('break3InRound_'+str(t1)+'_'+str(r), lowBound = 0, cat = pulp.LpContinuous) for t1 in teams for r in rounds}
|
|
# breakInRound= {(t1,r) : pulp.LpVariable('breakInRound_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for r in rounds}
|
|
# breaksTotal = pulp.LpVariable('breaksTotal', lowBound = 0, cat = pulp.LpContinuous)
|
|
|
|
tripToSingleTripElement = {(t1,d,c) : pulp.LpVariable('tripToSingleTripElement_'+str(t1)+'_'+str(d)+'_'+str(c), lowBound = 0, upBound = 0, cat = pulp.LpContinuous) for t1 in teams for d in days for (c,v1,v2,v3,v4) in tripElements[t1]}
|
|
tripToCluster = {(t1,r,c) : pulp.LpVariable('tripToCluster_'+str(t1)+'_'+str(r)+'_'+str(c), lowBound = 0, upBound = 0, cat = pulp.LpContinuous) for t1 in teams for r in rounds for c in clusters if not c in t_clusters[t1] and r<nRounds}
|
|
tripToClusterDaily = {(t1,d,c) : pulp.LpVariable('tripToClusterDaily_'+str(t1)+'_'+str(d)+'_'+str(c), lowBound = 0, upBound = 0, cat = pulp.LpContinuous) for t1 in realteams for d in days for c in clusters if not c in t_clusters[t1]}
|
|
tooManyTop4InRow= {(t1,r) : pulp.LpVariable('tooManyTop4InRow_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for r in rounds}
|
|
|
|
tooManyHomesInStadium= {(stadium,d) : pulp.LpVariable('tooManyHomesInStadium_'+str(stadium)+'_'+str(d), lowBound = 0, cat = pulp.LpContinuous) for stadium in stadiums for d in days+higherLeagueDayIds}
|
|
pairingVio= {(pair['id'],d) : pulp.LpVariable('pairingVio_'+str(pair['id'])+'_'+str(d), lowBound = 0, cat = pulp.LpContinuous) for pair in pairings for d in days+higherLeagueDayIds}
|
|
derbyMissing= {d : pulp.LpVariable('derbyMissing_'+str(d), lowBound = 0, cat = pulp.LpContinuous) for d in days}
|
|
|
|
breakVio = { (br['id'],t) : pulp.LpVariable('breakVio_'+ str(br['id'])+'_'+str(t) , lowBound = 0, cat = pulp.LpContinuous) for br in breaks for t in teams}
|
|
blockingVio = { bl['id'] : pulp.LpVariable('blockingVio_'+ str(bl['id']) , lowBound = 0, cat = pulp.LpContinuous) for bl in blockings}
|
|
# blockingVioTotal = pulp.LpVariable('blockingVioTotal', lowBound = 0, cat = pulp.LpContinuous)
|
|
|
|
hawVio = { haw['id'] : pulp.LpVariable('hawVio'+ str(haw['id']) , lowBound = 0, cat = pulp.LpContinuous) for haw in hawishes}
|
|
HawVioTooLess = { el : pulp.LpVariable('havviotooless_'+ str(el) , lowBound = 0, cat = pulp.LpContinuous) for haw in hawishes for el in elemHaWishes[haw['id']] }
|
|
HawVioTooMuch = { el : pulp.LpVariable('havviotoomuch_'+ str(el) , lowBound = 0, cat = pulp.LpContinuous) for haw in hawishes for el in elemHaWishes[haw['id']] }
|
|
# HawVioTotal = pulp.LpVariable('HawVioTotal', lowBound = 0, cat = pulp.LpContinuous)
|
|
encVio = { enc['id'] : pulp.LpVariable('encVio'+ str(enc['id']) , lowBound = 0, cat = pulp.LpContinuous) for enc in encwishes}
|
|
encVioTooLess = { el : pulp.LpVariable('encViotooless'+ str(enc['id'])+"_"+str(el) , lowBound = 0, cat = pulp.LpContinuous) for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
encVioTooMuch = { el : pulp.LpVariable('encViotoomuch'+ str(enc['id'])+"_"+str(el) , lowBound = 0, cat = pulp.LpContinuous) for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
# encVioTotal = pulp.LpVariable('encVioTotal', lowBound = 0, cat = pulp.LpContinuous)
|
|
confVio = { conf['id'] : pulp.LpVariable('confVio'+ str(conf['id']) , lowBound = 0, cat = pulp.LpContinuous) for conf in conferencewishes}
|
|
# broadVio = { d : pulp.LpVariable('broadVio'+ str(d) , lowBound = 0, cat = pulp.LpContinuous) for d in days}
|
|
broadVioTm = { (b.id, r): pulp.LpVariable('broadVioTm_'+ str(b.id) +"_"+ str(r) , lowBound = 0, cat = pulp.LpContinuous) for b in broadcastingwishes for r in rounds}
|
|
competitionVio = { (t,d) : pulp.LpVariable('competitionVio_'+ str(t) +'_'+ str(d) , lowBound = 0, cat = pulp.LpContinuous) for (t,d) in competitions.keys()}
|
|
gamesTooClose = { (t,d) : pulp.LpVariable('gamesTooClose_'+ str(t) +'_'+ str(d) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for d in days+higherLeagueDayIds if conflictDays[(t,d)]}
|
|
gamesTooClose2 = { (t,r) : pulp.LpVariable('gamesTooClose2_'+ str(t) +'_'+ str(r) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for r in rounds }
|
|
fixedGameVio = { (t1,t2,d) : pulp.LpVariable('fixedGameVio_'+ str(t1) +'_'+str(t2) +'_'+ str(d) , lowBound = 0, cat = pulp.LpContinuous) for (t1,t2,d) in fixedGames}
|
|
fixedGame2Vio = { (t1,t2,d) : pulp.LpVariable('fixedGame2Vio_'+ str(t1) +'_'+str(t2) +'_'+ str(d) , lowBound = 0, cat = pulp.LpContinuous) for (t1,t2,d) in fixedGames2}
|
|
missingGamesVio = { (t1,t2) : pulp.LpVariable('missingGamesVio_'+ str(t1) +'_'+str(t2) , lowBound = 0, cat = pulp.LpContinuous) for (t1,t2) in games}
|
|
|
|
home={}
|
|
away={}
|
|
home_time={}
|
|
away_time={}
|
|
away_in_cluster={}
|
|
away_in_cluster_day={}
|
|
|
|
getRoundDaysByBasicRound={br : [rd for r in getRealRounds[br] for rd in getRoundDaysByRound[r]] for br in basicRounds}
|
|
getMaxGameOnRoundDaysByBasicRound={br : sum ( roundDaysMax[rd]+excessGames[rd] for r in getRealRounds[br] for rd in getRoundDaysByRound[r]) for br in basicRounds}
|
|
|
|
if mathModelName in [ "Ligue 1" , "Costa Rica Premier League"]:
|
|
numPatterns= 2*nRounds1
|
|
patternRange=[p for p in range(1,numPatterns+1)]
|
|
patterns={}
|
|
for j in range (1,int(numPatterns/2)+1):
|
|
patterns[2*j-1,1]= 1
|
|
patterns[2*j,1]=0
|
|
for j in range(1,int(numPatterns/2)+1):
|
|
for i in range (2,int(numPatterns/2)+1):
|
|
patterns[2*j-1,i]= 1-patterns[2*j-1,i-1]
|
|
if i>= 1 and i==j :
|
|
patterns[2*j-1,i]=1-patterns[2*j-1,i]
|
|
patterns[2*j,i]= 1-patterns[2*j-1,i]
|
|
|
|
forbiddenPatterns=[]
|
|
if use2BreakPatterns :
|
|
p_cntr=numPatterns
|
|
for b1 in rounds1:
|
|
for b2 in rounds1:
|
|
if b1+2<=b2 and b1>1 and b2-b1<nTeams-3:
|
|
print ("breaks ", b1, b2 )
|
|
p_cntr+=2
|
|
for r in rounds1:
|
|
np=1
|
|
if r>1:
|
|
np = 1-patterns[p_cntr-1,r-1]
|
|
if r in [b1,b2]:
|
|
np=1-np
|
|
patterns[p_cntr-1,r]=np
|
|
patterns[p_cntr,r]=1-np
|
|
patternRange.append(p_cntr-1)
|
|
patternRange.append(p_cntr)
|
|
|
|
for p in [p_cntr-1 ,p_cntr]:
|
|
p_nhome_games = sum ([patterns[p,d] for d in rounds1 ])
|
|
print ( " - ", 100+p , " :" ,end="")
|
|
for d in rounds1:
|
|
print (patterns[p,d] , end="" )
|
|
if p_nhome_games < nTeams/2-1 or p_nhome_games > nTeams/2 :
|
|
print (" ** BAD ** ", end="")
|
|
forbiddenPatterns.append(p)
|
|
print (" sum : " , sum ([patterns[p,d] for d in rounds1 ]))
|
|
|
|
forbiddenStarterPatterns = [ p for p in patternRange if not thisSeason.startWithBreakAllowed and patterns[p,1]==patterns[p,2]]
|
|
forbiddenEndPatterns = [ p for p in patternRange if not thisSeason.endWithBreakAllowed and patterns[p,nRounds1-1]==patterns[p,nRounds1]]
|
|
forbiddenPatterns+=forbiddenStarterPatterns+forbiddenEndPatterns
|
|
patternRange=[p for p in patternRange if p not in forbiddenPatterns]
|
|
print (forbiddenPatterns)
|
|
print (patternRange)
|
|
print ("getPhaseOfRound",getPhaseOfRound)
|
|
print ("getBasicRound",getBasicRound)
|
|
|
|
assignPattern2={(p,t1,ph) : pulp.LpVariable('assignPattern2_'+str(t1)+'_'+str(p)+'_'+str(ph), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for p in patternRange for t1 in realteams for ph in phases}
|
|
usePattern2={(p,ph) : pulp.LpVariable('usePat2_'+str(p) + '_' + str(ph), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for p in patternRange for ph in phases}
|
|
for ph in phases:
|
|
if runMode == 'New':
|
|
for p in patternRange:
|
|
model2+= usePattern2[(p,ph)]== sum([ assignPattern2[p,t,ph] for t in realteams])
|
|
if p%2==0:
|
|
model2+= usePattern2[(p,ph)]==usePattern2[p-1,ph]
|
|
# print ("complementaries " , p, p-1)
|
|
for t in realteams:
|
|
# every team one pattern
|
|
model2 += lpSum( assignPattern2[(p,t,ph)] for p in patternRange)==1 , "one_pattern_for_2_%s_%s"%(t,ph)
|
|
|
|
# for r in rounds:
|
|
# if r==1 or getBasicRound[r-1] != getBasicRound[r]:
|
|
# model2 += lpSum( homeInRound[(t,r2)] for r2 in rounds if getBasicRound[r2]==getBasicRound[r]) == lpSum(assignPattern2[(p,t,getPhaseOfRound[r])] * patterns[p,r-getPhaseOfRound[r]*nRounds1] for p in patternRange)
|
|
|
|
for r in basicRounds:
|
|
model2 += lpSum( homeInRound[(t,r2)] for r2 in getRealRounds[r]) == lpSum(assignPattern2[(p,t,getPhaseOfBasicRound[r])] * patterns[p,r-getPhaseOfBasicRound[r]*nRounds1] for p in patternRange)
|
|
|
|
# for cs in currentSolution:
|
|
# setLB(x[(cs[0],cs[1],(cs[2],cs[3]))],1)
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=20,msg=1))
|
|
|
|
for t in higherTeams :
|
|
for d in days+higherLeagueDayIds:
|
|
away[t,d] = 0
|
|
home[t,d] = 0
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
away_time[t,d,tm] = 0
|
|
home_time[t,d,tm] = 0
|
|
|
|
print ("READING UPPER GAMES", higherLeagueDayIds)
|
|
|
|
for (dy,t1,t2,rd,tm) in higherGames:
|
|
dy2 = getDayByDateTime[getDateTimeDay[dy]]
|
|
home[t1,dy2] = 1
|
|
away[t2,dy2] = 1
|
|
if tm in getIdByTime.keys():
|
|
home_time[t1,dy2,getIdByTime[tm]] = 1
|
|
away_time[t2,dy2,getIdByTime[tm]] = 1
|
|
|
|
for t in realteams:
|
|
for d in higherLeagueDayIds:
|
|
away[t,d] = 0
|
|
home[t,d] = 0
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
away_time[t,d,tm] = 0
|
|
home_time[t,d,tm] = 0
|
|
|
|
for d in days:
|
|
away[t,d] = lpSum([x[(t2,t,rd)] for t2 in opponents[t] for rd in getRoundDaysByDay[d]]) or pulp.LpVariable('away'+str(t)+'_'+str(d), lowBound = 0, upBound = 0, cat = pulp.LpContinuous)
|
|
home[t,d] = lpSum([x[(t,t2,rd)] for t2 in opponents[t] for rd in getRoundDaysByDay[d]]) or pulp.LpVariable('home'+str(t)+'_'+str(d), lowBound = 0, upBound = 0, cat = pulp.LpContinuous)
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for t2 in opponents[t]:
|
|
# print (t,t2,getTeamById[t], getTeamById[t2], (t,t2) in games )
|
|
# if (t,t2) in games:
|
|
for rd in getRoundDaysByDay[d]:
|
|
# TODO: HOTFIX
|
|
if (x[(t2,t,rd)] != 0):
|
|
model2+= x[(t2,t,rd)] == lpSum([ x_time[(t2,t,rd,tm)] for tm in times])
|
|
for tm in times:
|
|
away_time[t,d,tm] = lpSum([x_time[(t2,t,rd,tm)] for t2 in opponents[t] for rd in getRoundDaysByDay[d] ])
|
|
home_time[t,d,tm] = lpSum([x_time[(t,t2,rd,tm)] for t2 in opponents[t] for rd in getRoundDaysByDay[d] ])
|
|
|
|
for c in clusters:
|
|
away_in_cluster_day[t,d,c] = lpSum([x[(t2,t,rd)] for t2 in cluster_teams[c] for rd in getRoundDaysByDay[d] if t2 in opponents[t]])
|
|
|
|
for t in realteams:
|
|
tms = [t] + higherTeamsOf[t]
|
|
print (tms)
|
|
for d in days+higherLeagueDayIds :
|
|
model2 += home[(t,d)]+away[(t,d)] <= 1
|
|
if len(higherTeamsOf[t])>0 and d in upperAndLowerLeagueIds:
|
|
model2 += lpSum([ home[(t1,d)]+away[(t1,d)] for t1 in tms ]) <= 1 + gamesTooClose[t,d]
|
|
|
|
if conflictDays[(t,d)]:
|
|
# print (t,getNiceDay[d],conflictDays[(t,d)])
|
|
# for d2 in conflictDays[(t,d)]:
|
|
# if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'A','H')] ):
|
|
# print (" - " ,getNiceDay[d2] ,getDateTimeDay[d2]-getDateTimeDay[d] , datetime.timedelta(days=minRest[(t,'A','A')]) )
|
|
# model2 += lpSum([home[(t,d2)]+away[(t,d2)] for d2 in conflictDays[(t,d)]]) <= 1+ gamesTooClose[t,d]
|
|
# if len(tms)>1:
|
|
# print (lpSum([ home[(t1,d)] for t1 in tms ]) +lpSum([ home[(t1,d2)] for d2 in conflictDays[(t,d)] for t1 in tms if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'H','H')] )] ))
|
|
model2 += lpSum([ home[(t1,d)] for t1 in tms ]) +lpSum([ home[(t1,d2)] for d2 in conflictDays[(t,d)] for t1 in tms if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'H','H')] )] ) <= 1+ gamesTooClose[t,d]
|
|
model2 += lpSum([ home[(t1,d)] for t1 in tms ]) +lpSum([ away[(t1,d2)] for d2 in conflictDays[(t,d)] for t1 in tms if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'H','A')] )] ) <= 1+ gamesTooClose[t,d]
|
|
model2 += lpSum([ away[(t1,d)] for t1 in tms ]) +lpSum([ home[(t1,d2)] for d2 in conflictDays[(t,d)] for t1 in tms if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'A','H')] )] ) <= 1+ gamesTooClose[t,d]
|
|
model2 += lpSum([ away[(t1,d)] for t1 in tms ]) +lpSum([ away[(t1,d2)] for d2 in conflictDays[(t,d)] for t1 in tms if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'A','A')] )] ) <= 1+ gamesTooClose[t,d]
|
|
# model2 += home[(t,d)]+lpSum([ away[(t,d2)] for d2 in conflictDays[(t,d)] if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'H','A')]) ] ) <= 1+ gamesTooClose[t,d]
|
|
# model2 += away[(t,d)]+lpSum([ home[(t,d2)] for d2 in conflictDays[(t,d)] if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'A','H')]) ] ) <= 1+ gamesTooClose[t,d]
|
|
# model2 += away[(t,d)]+lpSum([ away[(t,d2)] for d2 in conflictDays[(t,d)] if d2!=d and getDateTimeDay[d2]-getDateTimeDay[d] <= datetime.timedelta(days=minRest[(t,'A','A')]) ] ) <= 1+ gamesTooClose[t,d]
|
|
|
|
|
|
for t in realteams:
|
|
for r in rounds:
|
|
# awayInRound[t,r] = lpSum([x[(t2,t,dr)] for t2 in teams for dr in getRoundDaysByRound[r]])
|
|
# homeInRound[t,r] = lpSum([x[(t,t2,dr)] for t2 in teams for dr in getRoundDaysByRound[r]])
|
|
|
|
if thisSeason.gamesPerRound=="one day":
|
|
# model2 += homeInRound[(t,r)] == lpSum([home[(t,d)] for (r2,d) in getRoundDaysByRound[r]])
|
|
model2 += homeInRound[(t,r)] == lpSum([x[(t,t2,rd)] for t2 in opponents[t] for rd in getRoundDaysByRound[r]])
|
|
model2 += awayInRound[(t,r)] == lpSum([x[(t2,t,rd)] for t2 in opponents[t] for rd in getRoundDaysByRound[r]])
|
|
else:
|
|
model2 += homeInRound[(t,r)] == lpSum([x[(t,t2,getRoundDaysByRound[r][0])] for t2 in opponents[t] ])
|
|
model2 += awayInRound[(t,r)] == lpSum([x[(t2,t,getRoundDaysByRound[r][0])] for t2 in opponents[t] ])
|
|
|
|
model2 += homeInRound[(t,r)] + awayInRound[(t,r)] <= 1
|
|
if r>=3:
|
|
model2 += break3InRound[(t,r)] +2>= homeInRound[(t,r-2)]+homeInRound[(t,r-1)]+homeInRound[(t,r)]
|
|
model2 += break3InRound[(t,r)] +2>= awayInRound[(t,r-2)]+awayInRound[(t,r-1)]+awayInRound[(t,r)]
|
|
|
|
if r>1:
|
|
if thisSeason.gamesPerRound=="one day":
|
|
model2 += lpSum([x[(t,t4,d)]+x[(t4,t,d)] for t4 in top4 for d in (getRoundDaysByRound[r-1]+getRoundDaysByRound[r]) if t4 in opponents[t] ]) <= 1+tooManyTop4InRow[(t,r)]
|
|
else:
|
|
model2 += lpSum([x[(t,t4,d)]+x[(t4,t,d)] for t4 in top4 for d in [getRoundDaysByRound[r-1][0],getRoundDaysByRound[r][0]] if t4 in opponents[t] ]) <= 1+tooManyTop4InRow[(t,r)]
|
|
|
|
for c in clusters:
|
|
if thisSeason.gamesPerRound=="one day":
|
|
away_in_cluster[t,r,c] = lpSum([x[(t2,t,rd)] for t2 in cluster_teams[c] for rd in getRoundDaysByRound[r] if t2 in opponents[t] ])
|
|
else:
|
|
away_in_cluster[t,r,c] = lpSum([x[(t2,t,getRoundDaysByRound[r][0])] for t2 in cluster_teams[c] if t2 in opponents[t] ])
|
|
|
|
|
|
print ("fixedGamesRounds:" ,fixedGamesRounds)
|
|
for (t1,t2,r) in fixedGamesRounds:
|
|
model2+= lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[r] ] )==1
|
|
print ("fix ", t1,t2,r, lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[r]] ))
|
|
|
|
|
|
if sharedStadiums:
|
|
useStadiumTimeSlot = { (t,d,s) : pulp.LpVariable('useStadiumTimeSlot_'+str(t)+"_"+str(d)+"_"+str(s) , lowBound = 0, upBound = 1, cat = pulp.LpContinuous ) for (t,d) in t_site_bestTimeSlots.keys() for (p,s) in t_site_bestTimeSlots[(t,d)]}
|
|
nonIceGame = { (t,d) : pulp.LpVariable('nonIceGame_'+str(t)+"_"+str(d) , lowBound = 0, upBound = 1, cat = pulp.LpContinuous ) for (t,d) in home.keys()}
|
|
for (t,d) in t_site_bestTimeSlots.keys():
|
|
if len(t_site_bestTimeSlots[t,d])==0 :
|
|
model2 += home[(t,d)] == 0 + nonIceGame[(t,d)]
|
|
else:
|
|
model2 += home[(t,d)] == lpSum([useStadiumTimeSlot[(t,d,s)] for (p,s) in t_site_bestTimeSlots[t,d]])+ nonIceGame[(t,d)]
|
|
if "AllowGamesWithoutIce" not in special_wishes_active:
|
|
model2 += nonIceGame[(t,d)] == 0
|
|
|
|
getStadiumTimeSlotsPerDay={ (st.id,d) : [] for st in theseStadiums for d in days }
|
|
# for s in sorted(getStadiumTimeSlot.keys()):
|
|
# print (s,getStadiumTimeSlot[s])
|
|
for (t,d,s) in useStadiumTimeSlot.keys():
|
|
getStadiumTimeSlotsPerDay[getStadiumTimeSlot[s]['stadium_id'],d].append((t,s))
|
|
# print (t,d,s)
|
|
# print (getStadiumTimeSlot[s])
|
|
|
|
for st in theseStadiums:
|
|
for d in days :
|
|
if len(getStadiumTimeSlotsPerDay[st.id,d])>1:
|
|
# print ("CONFLICTS?",st, getNiceDay[d], getStadiumTimeSlotsPerDay[st.id,d])
|
|
conflicts_all = [ sorted(list(incompatible_timslots[s])) for t,s in getStadiumTimeSlotsPerDay[st.id,d]]
|
|
conflicts =[]
|
|
for c in conflicts_all:
|
|
if c not in conflicts:
|
|
conflicts.append(c)
|
|
print ("conficts ", conflicts)
|
|
for c in conflicts:
|
|
conflicting_slots = [useStadiumTimeSlot[(t,d,s)] for t,s in getStadiumTimeSlotsPerDay[st.id,d] if s in c ]
|
|
# print ("not at same time " ,conflicting_slots)
|
|
if len(conflicting_slots)>1:
|
|
model2 += lpSum(conflicting_slots) <=1
|
|
print ( "############## constraint built ")
|
|
|
|
# cntr =0
|
|
# for t in teams:
|
|
# for r in rounds:
|
|
# for c in real_clusters:
|
|
# if r>1 and runMode=='Improve':
|
|
# if gew['Trips']>0 and t_cluster[t]!=c \
|
|
# and parse(getNiceDay[earliestDay[r]])-parse(getNiceDay[latestDay[r-1]])<=datetime.timedelta(days=thisSeason.maxDistanceWithinTrip+1):
|
|
# model2 += tripToCluster[(t,r-1,c)] <= away_in_cluster[t,r-1,c]
|
|
# model2 += tripToCluster[(t,r-1,c)] <= away_in_cluster[t,r,c]
|
|
# tripToCluster[(t,r-1,c)].upBound=1
|
|
# # print ('considering trip of ' , getTeamById[t], ' in round ' , r , ' to cluster ' , c )
|
|
# cntr +=2
|
|
# else:
|
|
# model2 += tripToCluster[(t,r-1,c)] == 0
|
|
|
|
# if r==nRounds :
|
|
# model2 += tripToCluster[(t,r,c)] == 0
|
|
# print ("built ", cntr , " trip constraints")
|
|
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for t in realteams:
|
|
for d in onlyEarlyDays:
|
|
model2+= home_time[t,d,getIdByTime["Late"]]==0
|
|
model2+= away_time[t,d,getIdByTime["Late"]]==0
|
|
for d in onlyLateDays:
|
|
model2+= home_time[t,d,getIdByTime["Early"]]==0
|
|
model2+= away_time[t,d,getIdByTime["Early"]]==0
|
|
|
|
|
|
breakVioBalance = { t : pulp.LpVariable('breakVioBalance_'+str(t) , lowBound = 0, cat = pulp.LpContinuous) for t in realteams }
|
|
numBreaks = { t : lpSum([ breakVio[(bl['id'],t)] for bl in breaks ]) for t in realteams }
|
|
|
|
|
|
succBreaks = [ bl for bl in breaks if bl['round1']+1==bl['round2'] ]
|
|
|
|
if thisSeason.forbidDoubleBreaks:
|
|
for bl1 in succBreaks:
|
|
for bl2 in succBreaks:
|
|
if bl1['round2']+1==bl2['round1']:
|
|
for t in realteams:
|
|
model2+= homeInRound[t,bl1['round1']] + homeInRound[t,bl1['round2']] + awayInRound[t,bl2['round1']] + awayInRound[t,bl2['round2']] <= 3 + 0.2* breakVio[(bl1['id'],t)]
|
|
model2+= awayInRound[t,bl1['round1']] + awayInRound[t,bl1['round2']] + homeInRound[t,bl2['round1']] + homeInRound[t,bl2['round2']] <= 3 + 0.2* breakVio[(bl1['id'],t)]
|
|
|
|
for t in realteams:
|
|
for bl in breaks:
|
|
# print (getTeamById[t], realteams, getRoundDaysByRound[bl['round1']]+getRoundDaysByRound[bl['round2']] )
|
|
# model2+= breakVio[(bl['id'],t)] + 1 >= lpSum([x[(t,t2,rd)] for t2 in realteams for rd in getRoundDaysByRound[bl['round1']]+getRoundDaysByRound[bl['round2']] ])
|
|
# model2+= breakVio[(bl['id'],t)] + 1 >= lpSum([x[(t2,t,rd)] for t2 in realteams for rd in getRoundDaysByRound[bl['round1']]+getRoundDaysByRound[bl['round2']] ])
|
|
model2+= breakVio[(bl['id'],t)] + 1 >= homeInRound[t,bl['round1']] + homeInRound[t,bl['round2']]
|
|
model2+= breakVio[(bl['id'],t)] + 1 >= awayInRound[t,bl['round1']] + awayInRound[t,bl['round2']]
|
|
if bl['round2'] + 1 <= nRounds:
|
|
model2+= 0.2+breakVio[(bl['id'],t)] + 2 >= homeInRound[t,bl['round1']] + homeInRound[t,bl['round2']] + homeInRound[t,bl['round2']+1]
|
|
model2+= 0.2+breakVio[(bl['id'],t)] + 2 >= awayInRound[t,bl['round1']] + awayInRound[t,bl['round2']] + awayInRound[t,bl['round2']+1]
|
|
|
|
if balanceBreaks:
|
|
model2+= numBreaks[t] <= lpSum([ numBreaks[t2] for t2 in realteams])/len(realteams) + breakVioBalance[t]
|
|
for t2 in teams:
|
|
if half_symmetry_offset==0:
|
|
model2+= numBreaks[t2] <= 4
|
|
model2+= numBreaks[t2] >= 3
|
|
else:
|
|
model2+= numBreaks[t2] <= 5
|
|
model2+= numBreaks[t2] >= 1
|
|
print ("balancing Breaks ")
|
|
|
|
for bl in breaks:
|
|
model2+= breakVio[(bl['id'],t)] <= 2 - homeInRound[t,bl['round1']] - awayInRound[t,bl['round2']]
|
|
model2+= breakVio[(bl['id'],t)] <= 2 - awayInRound[t,bl['round1']] - homeInRound[t,bl['round2']]
|
|
|
|
|
|
|
|
if not evalRun:
|
|
if not thisSeason.minBreaks and len(breaks)>0 and not balanceBreaks:
|
|
for p in phases:
|
|
# print ("Don't allow breaks for ",t, " in phase ", p)
|
|
model2+= lpSum([breakVio[(bl['id'],t)] for bl in breaks if getPhaseOfRound[bl['round1']]==p and getPhaseOfRound[bl['round2']]==p]) <= thisSeason.initBreaks
|
|
|
|
if mathModelName in [ "Ligue 1"]:
|
|
model2+= lpSum([breakVio[(bl['id'],t)] for bl in breaks ]) <= 4
|
|
|
|
if not thisSeason.startWithBreakAllowed:
|
|
model2+= homeInRound[t,1] + homeInRound[t,2] <= 1
|
|
model2+= awayInRound[t,1] + awayInRound[t,2] <= 1
|
|
if not thisSeason.endWithBreakAllowed:
|
|
print ("NO BREAK FOR " , t , " in rounds " ,nRounds-1, nRounds)
|
|
model2+= homeInRound[t,nRounds-1] + homeInRound[t,nRounds] <= 1
|
|
model2+= awayInRound[t,nRounds-1] + awayInRound[t,nRounds] <= 1
|
|
|
|
# print ('\n')
|
|
# for p in phases:
|
|
# for d in getDaysOfPhase[p] :
|
|
# print (p,d, getRoundDaysByDay[d])
|
|
|
|
# return ''
|
|
|
|
if len (fixedGamesRounds)==0:
|
|
for br in basicRounds:
|
|
imp_rds= getRoundDaysByBasicRound[br] if thisSeason.gamesPerRound=="one day" else [getRoundDaysByBasicRound[br][0]]
|
|
# print (br, imp_rds)
|
|
for t1 in realteams:
|
|
model2 += homeInBasicRound[(t1,br)] == lpSum([x[(t1,t2,rd)] for t2 in opponents[t1] for rd in imp_rds])
|
|
model2 += awayInBasicRound[(t1,br)] == lpSum([x[(t2,t1,rd)] for t2 in opponents[t1] for rd in imp_rds])
|
|
for t2 in opponents[t1]:
|
|
if (t1,t2) in games:
|
|
model2 += gameInBasicRound[(t1,t2,br)] == lpSum([ x[(t1,t2,rd)] for rd in imp_rds ])
|
|
|
|
# print ("§§§",t1,t2,br,gameInBasicRound[(t1,t2,br)].upBound )
|
|
|
|
# for ttr in x.keys():
|
|
# makeIntVar(x[ttr])
|
|
# model2.solve(GUROBI(MIPGap=0.3, TimeLimit=180,msg=1))
|
|
|
|
|
|
|
|
getDays[0] =[]
|
|
|
|
# return 2
|
|
for d in days+higherLeagueDayIds:
|
|
for stadium in stadiums:
|
|
factor = 0.001 if len(teamsOfStadium[stadium])==2 else 1.0
|
|
# print (stadium, teamsOfStadium[stadium] , len(teamsOfStadium[stadium]))
|
|
model2 += lpSum([home[t,d] for t in teamsOfStadium[stadium]]) <= 1 + factor*tooManyHomesInStadium[(stadium,d)]
|
|
|
|
if thisSeason.useFeaturePairings:
|
|
for pair in pairings:
|
|
# print (pair)
|
|
pDaysSets = []
|
|
for d in days+higherLeagueDayIds:
|
|
pTeams = [pair['team1_id'], pair['team2_id']]
|
|
pDays = [d]
|
|
if pair['dist'] ==1 and nextDay[d]!=-1:
|
|
pDays.append(nextDay[d])
|
|
if pair['dist'] in [3,7]:
|
|
pDays=getDays[getRoundByDay[d]] + getHigherDaysByRound[getRoundByDay[d]]
|
|
# print ( getNiceDay[d], getRoundByDay[d], getDays[getRoundByDay[d]] , " +" ,getHigherDaysByRound[getRoundByDay[d]])
|
|
factor = 1.0
|
|
if len(pDays)>0 and pDays not in pDaysSets:
|
|
pDaysSets.append(pDays.copy())
|
|
# print ("+++ ")
|
|
# else:
|
|
# print ("--- ")
|
|
|
|
# if pair['prio'] =='A':
|
|
# factor = 0.1
|
|
for pDays in pDaysSets:
|
|
d= pDays[0]
|
|
print ("Treating day set starting with day " , getNiceDay[d], " ", pDays)
|
|
if pair['dist'] in [2,6] and thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
if pair['type']== "Home":
|
|
if pair['dist']<=3:
|
|
model2 += lpSum([home_time[t,d,tm] for t in pTeams]) <= 1 + factor*pairingVio[(pair['id'],d)]
|
|
else:
|
|
model2 += home_time[pair['team1_id'],d,tm] - home_time[pair['team2_id'],d,tm] <= factor*pairingVio[(pair['id'],d)]
|
|
model2 += home_time[pair['team2_id'],d,tm] - home_time[pair['team1_id'],d,tm] <= factor*pairingVio[(pair['id'],d)]
|
|
else:
|
|
if pair['dist']<=3:
|
|
model2 += lpSum([home_time[t,d,tm] + away_time[t,d,tm] for t in pTeams]) <= 1 + pairingVio[(pair['id'],d)]
|
|
else:
|
|
model2 += home_time[pair['team1_id'],d,tm] + away_time[pair['team1_id'],d,tm] - home_time[pair['team2_id'],d,tm] - away_time[pair['team2_id'],d,tm] <= factor*pairingVio[(pair['id'],d)]
|
|
model2 += home_time[pair['team2_id'],d,tm] + away_time[pair['team2_id'],d,tm] - home_time[pair['team1_id'],d,tm] - away_time[pair['team1_id'],d,tm] <= factor*pairingVio[(pair['id'],d)]
|
|
|
|
else:
|
|
if pair['type']== "Home":
|
|
if pair['dist']<=3:
|
|
model2 += lpSum([home[t,dd] for t in pTeams for dd in pDays]) <= 1 + factor*pairingVio[(pair['id'],d)]
|
|
else:
|
|
model2 += lpSum([home[pair['team1_id'],dd] - home[pair['team2_id'],dd] for dd in pDays]) <= factor*pairingVio[(pair['id'],d)]
|
|
model2 += lpSum([home[pair['team2_id'],dd] - home[pair['team1_id'],dd] for dd in pDays]) <= factor*pairingVio[(pair['id'],d)]
|
|
else:
|
|
if pair['dist']<=3:
|
|
model2 += lpSum([home[t,dd] + away[t,dd] for t in pTeams for dd in pDays]) <= 1 + pairingVio[(pair['id'],d)]
|
|
else:
|
|
model2 += lpSum([home[pair['team1_id'],dd] + away[pair['team1_id'],dd] - home[pair['team2_id'],dd] - away[pair['team2_id'],dd] for dd in pDays]) <= factor*pairingVio[(pair['id'],d)]
|
|
model2 += lpSum([home[pair['team2_id'],dd] + away[pair['team2_id'],dd] - home[pair['team1_id'],dd] - away[pair['team1_id'],dd] for dd in pDays]) <= factor*pairingVio[(pair['id'],d)]
|
|
|
|
|
|
# print ("fixedGames:" ,fixedGames)
|
|
for (t1,t2,d) in fixedGames:
|
|
model2+= lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[getRoundByDay[d]] ] )==1 - fixedGameVio[(t1,t2,d)]
|
|
# if not thisSeason.useFeatureKickOffTime or not currentKickoffTimes[(t1,t2,d)] :
|
|
# model2+= lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[getRoundByDay[d]] ] )==1 - fixedGameVio[(t1,t2,d)]
|
|
# else:
|
|
# model2+= lpSum ( [x_time[(t1,t2,rd,currentKickoffTimes[(t1,t2,d)])] for rd in getRoundDaysByRound[getRoundByDay[d]] ] )==1 - fixedGameVio[(t1,t2,d)]
|
|
if not thisScenario.allowFixedVio:
|
|
model2+= fixedGameVio[(t1,t2,d)]==0
|
|
print ("HARD FIXING TO ROUND", getRoundByDay[d], t1,t2,d )
|
|
else:
|
|
print ("SOFT FIXING TO ROUND", getRoundByDay[d], t1,t2,d )
|
|
|
|
for (t1,t2,d) in fixedGames2:
|
|
if not thisSeason.useFeatureKickOffTime or not currentKickoffTimes[(t1,t2,d)] :
|
|
model2+= lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByDay[d]] )== 1 - fixedGame2Vio[(t1,t2,d)]
|
|
else:
|
|
model2+= lpSum ( [x_time[(t1,t2,rd,currentKickoffTimes[(t1,t2,d)])] for rd in getRoundDaysByDay[d]] )== 1 - fixedGame2Vio[(t1,t2,d)]
|
|
if not thisScenario.allowFixedVio:
|
|
model2+= fixedGame2Vio[(t1,t2,d)]==0
|
|
print ("HARD FIXING " , t1,t2,d , (t1,t2,d) in fixedGameVio.keys(), getRoundDaysByDay[d] , getRoundByDay[d] )
|
|
else:
|
|
print ("SOFT FIXING " , t1,t2,d , (t1,t2,d) in fixedGameVio.keys(), getRoundDaysByDay[d] )
|
|
|
|
# return ''
|
|
# use_currentSolution= False
|
|
# for (t1,t2,d) in fixedRoundGames:
|
|
# # if thisScenario.allowFixedVio:
|
|
# # model2 += lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[getRoundByDay[d]]] )==1 - fixedRoundGameVio[(t1,t2,d)]
|
|
# # else:
|
|
# model2 += lpSum ( [x[(t1,t2,rd)] for rd in getRoundDaysByRound[getRoundByDay[d]]] )==1
|
|
|
|
# # TESTING
|
|
|
|
|
|
use_currentSolution= False
|
|
|
|
currentGameCntr = { (t1,t2) :0 for t1 in teams for t2 in teams }
|
|
|
|
if runMode=='Improve' and len(currentSolution) > len(fixedGames) + len(fixedGames2 ) :
|
|
use_currentSolution= True
|
|
|
|
# if use_currentSolution and len(currentSolution) !=len(fixedGames):
|
|
|
|
teamGameCntr = { (t,r) :0 for t in teams for r in rounds }
|
|
|
|
if use_currentSolution:
|
|
for cs in currentSolution:
|
|
if len(cs)>=4:
|
|
t1=cs[0]
|
|
t2=cs[1]
|
|
r=cs[2]
|
|
d=cs[3]
|
|
if (t1,t2,(r,d)) in x.keys():
|
|
currentGameCntr[(t1,t2)] +=1
|
|
setLB(x[(t1,t2,(r,d))],1)
|
|
teamGameCntr[t1,r]+=1
|
|
teamGameCntr[t2,r]+=1
|
|
# if t1==16770:
|
|
# print ("fixing " , t1 , t2, r ,d)
|
|
|
|
# for (t,r) in teamGameCntr.keys():
|
|
# if teamGameCntr[(t,r)]!=1:
|
|
# print (getTeamById[t], " plays " ,teamGameCntr[(t,r)] , " games in round ", r )
|
|
|
|
|
|
# sing for 16770 16766 0 2
|
|
|
|
# for ttr in x.keys():
|
|
# makeIntVar(x[ttr])
|
|
|
|
|
|
# if len(currentSolution) ==len(fixedGames):
|
|
# print ("alles fixieren")
|
|
|
|
# print ("TESTING")
|
|
# for ttr in x.keys():
|
|
# makeIntVar(x[ttr])
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=40,msg=1))
|
|
# print ("TESTING DONE")
|
|
|
|
|
|
|
|
# print ("days " , days)
|
|
for d in days:
|
|
model2 += lpSum([x[(t1,t2,rd)] for (t1,t2) in games for rd in getRoundDaysByDay[d] if distance[getTeamById[t1],getTeamById[t2]]<=thisSeason.maxDistanceDerby ]) >= nDerbies[d] - derbyMissing[d]
|
|
minG = sum([ roundDaysMin[rd] - deficientGames[rd] for rd in getRoundDaysByDay[d]])
|
|
maxG = sum([ roundDaysMax[rd] + excessGames[rd] for rd in getRoundDaysByDay[d]])
|
|
# print (getNiceDay[d] , maxG)
|
|
# if minG<3 :
|
|
if minG>0 :
|
|
model2 += lpSum([ home[(t,d)] for t in realteams]) >= minG
|
|
model2 += lpSum([ home[(t,d)] for t in realteams]) <= maxG
|
|
|
|
if len(getRoundDaysByDay[d])>1:
|
|
for rd in getRoundDaysByDay[d]:
|
|
if roundDaysMin[rd]>0:
|
|
model2 += lpSum([x[(t1,t2,rd)] for (t1,t2) in games ] ) >= roundDaysMin[rd] - deficientGames[rd]
|
|
# model2 += lpSum([x[(t1,t2,rd)] for (t1,t2) in games ] ) >= roundDaysMin[rd]
|
|
print ("At least ",roundDaysMin[rd] , " on " , rd)
|
|
model2 += lpSum([x[(t1,t2,rd)] for (t1,t2) in games ] ) <= roundDaysMax[rd] + excessGames[rd]
|
|
|
|
print ("rounds " , rounds, nRounds)
|
|
for r in rounds:
|
|
# one game a round for everyone
|
|
for t1 in realteams:
|
|
if thisSeason.gamesPerRound=="one day":
|
|
cnstr = lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for t2 in opponents[t1] for rd in getRoundDaysByRound[r]] )
|
|
if len(cnstr) > 0:
|
|
model2 += cnstr <= 1
|
|
else:
|
|
print ( getRoundDaysByRound[r], opponents[t1])
|
|
if len(getRoundDaysByRound[r])>0:
|
|
for rd in getRoundDaysByRound[r]:
|
|
if rd==getRoundDaysByRound[r][0]:
|
|
model2 += lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for t2 in opponents[t1]] ) <= 1
|
|
else:
|
|
for t2 in opponents[t1]:
|
|
model2 += x[(t1,t2,rd)] == x[(t1,t2,getRoundDaysByRound[r][0])]
|
|
# print ("linking ", getRoundDaysByRound[r][0] , " to ", rd , " game " , t1, t2)
|
|
if len(getRoundDaysByRound[r])>1 and False:
|
|
for rd in getRoundDaysByRound[r]:
|
|
for t1 in realteams:
|
|
model2 += lpSum([home[t1,rd[1]] + away[t1,rd[1]]] ) <= 1
|
|
|
|
# exit(0)
|
|
print ("realteams " , realteams)
|
|
|
|
print ("taking care of right numbers of games ... " )
|
|
cntr= 0
|
|
|
|
if not specialGameControl:
|
|
for (t1,t2) in realgames:
|
|
if undirectedGameCntr[(t1,t2)]==0:
|
|
model2 += lpSum([x[(t1,t2,rd)] for rd in roundDays] ) == gameCntr[(t1,t2)] - missingGamesVio[(t1,t2)]
|
|
else:
|
|
# model2 += lpSum([x[(t1,t2,rd)] for rd in roundDays] ) == gameCntr[(t1,t2)]+undirectedGameCntr[(t1,t2)] - missingGamesVio[(t1,t2)]
|
|
model2 += missingGamesVio[(t1,t2)] >= gameCntr[(t1,t2)] - lpSum([x[(t1,t2,rd)] for rd in roundDays] )
|
|
model2 += missingGamesVio[(t1,t2)] >= gameCntr[(t1,t2)]+gameCntr[(t2,t1)]+undirectedGameCntr[(t1,t2)] - lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for rd in roundDays] )
|
|
model2 += lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for rd in roundDays] ) <= gameCntr[(t1,t2)]+gameCntr[(t2,t1)]+undirectedGameCntr[(t1,t2)]
|
|
|
|
missingGamesVio[(t1,t2)].upBound= max(0,gameCntr[(t1,t2)]+undirectedGameCntr[(t1,t2)] - currentGameCntr[(t1,t2)])
|
|
|
|
# print (t1,t2,gameCntr[(t1,t2)], currentGameCntr[(t1,t2)] , lpSum([x[(t1,t2,rd)] for rd in roundDays] ) )
|
|
|
|
if thisSeason.useFeatureOpponentMatrix and False:
|
|
gameCntr = { (t1,t2) : 0 for t1 in teams for t2 in teams }
|
|
for gm in gameRequirements:
|
|
gameCntr[(gm.team1.id,gm.team2.id)] = gm.number
|
|
if gm.number>0:
|
|
# print ("++++ " ,gm)
|
|
if gm.number <= 0.5*nPhases or currentGameCntr[(gm.team1.id,gm.team2.id)]==gm.number:
|
|
model2 += lpSum([x[(gm.team1.id,gm.team2.id,rd)] for rd in roundDays] ) == gm.number
|
|
# print ("EQU " , gm)
|
|
else:
|
|
model2 += lpSum([x[(gm.team1.id,gm.team2.id,rd)] for rd in roundDays] ) == gm.number - missingGamesVio[(gm.team1.id,gm.team2.id)]
|
|
# print ("MAX " , gm)
|
|
model2 += missingGamesVio[(gm.team1.id,gm.team2.id)] <= gm.number -0.5*nPhases
|
|
print ("games still missing for " , gm.team1.id, gm.team2.id, currentGameCntr[(gm.team1.id,gm.team2.id)] , gm.number)
|
|
|
|
print ("... done" )
|
|
|
|
# print (missingGamesVio.keys())
|
|
|
|
|
|
if not evalRun:
|
|
for (t1,t2) in realgames:
|
|
# every pair plays each other in each phase once
|
|
for p in phases:
|
|
if p<len(phases)-1 or True: # phase violation in last phase possible if it contained more rounds than necessary
|
|
if t_usePhases[t1] or t_usePhases[t2]:
|
|
if thisSeason.groupBased and len(noPlayRounds[t1])>0 and noPlayRounds[t1]==noPlayRounds[t2]:
|
|
relDays = []
|
|
phaseLength= int(len(playRounds[t1])/nPhases+0.5)
|
|
for rr in playRounds[t1][p*phaseLength:(p+1)*phaseLength]:
|
|
relDays+=getDays[rr]
|
|
print ("adding days of round ", rr , " to phase ", p)
|
|
else:
|
|
relDays = getDaysOfPhase[p]
|
|
model2 += lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for d in relDays for rd in getRoundDaysByDay[d] ] ) <= 1
|
|
# print (len(relDays),"reldays")
|
|
# print (getTeamById[t1],getTeamById[t2], sum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for d in relDays for rd in getRoundDaysByDay[d] ] ))
|
|
|
|
if not evalRun :
|
|
for t in realteams:
|
|
if t_usePhases[t] and thisSeason.distributeHomeGamesEvenlyOverPhases:
|
|
for p in phases:
|
|
rds = [r for r in rounds if getPhaseOfRound[r]==p ]
|
|
nblocked =[ r for r in noHomeRounds[t] if r in rds]
|
|
print (p, len(rds), len(nblocked), rds,nblocked, getTeamById[t])
|
|
for p in phases:
|
|
phaseLength= int(len(playRounds[t])/nPhases+0.5)
|
|
model2 += lpSum([ home[(t,d)] for d in getDaysOfPhase[p] ] ) <= int(phaseLength/2+1)
|
|
|
|
if thisSeason.minRoundsBetweenGameOfSameTeams>0:
|
|
for r in rounds:
|
|
if r +thisSeason.minRoundsBetweenGameOfSameTeams <=nRounds:
|
|
rds = [ ]
|
|
for r2 in range(r,r+thisSeason.minRoundsBetweenGameOfSameTeams+1):
|
|
rds+=getRoundDaysByRound[r2]
|
|
rds2 = [ ]
|
|
for r2 in range(r,r+int (0.5*thisSeason.minRoundsBetweenGameOfSameTeams)):
|
|
rds2+=getRoundDaysByRound[r2]
|
|
# print ("ONLY ONE IN " , rds)
|
|
# print ("ONLY ONE IN " , rds2)
|
|
for t1 in realteams:
|
|
for t2 in realteams:
|
|
if t1<t2 and (gameCntr[(t1,t2)]*gameCntr[(t2,t1)]>0 or x_round[(t1,t2,r)]!=0) :
|
|
# model2 += sum([ (x[(t1,t2, rd)]+x[(t2,t1,rd)]) for rd in rds ]) <= 1 + gamesTooClose2[t1,r]
|
|
model2 += sum([ (x[(t1,t2, rd)]+x[(t2,t1,rd)]) for rd in rds ]) <= 1
|
|
|
|
|
|
if thisSeason.lastRoundSync:
|
|
for g in displayGroups.keys():
|
|
affectedRounds = set([r for (r,d) in finalRoundDays])
|
|
print ("affectedRounds", affectedRounds)
|
|
if thisSeason.useFeatureKickOffTime:
|
|
print ("sync time ", g, " " , displayGroups[g], " " , finalRoundDays, " ", times)
|
|
for r in affectedRounds:
|
|
model2 += lpSum([lastRoundPlayed[(g,rd,tm)] for rd in finalRoundDays for tm in times if rd[0]==r ]) == 1
|
|
# model2 += lpSum([lastRoundPlayed[(g,rd,tm)] for rd in finalRoundDays for tm in times]) == len(affectedRounds)
|
|
for t in displayGroups[g]:
|
|
for rd in finalRoundDays:
|
|
for tm in times:
|
|
model2+= home_time[t,rd[1],tm]+ away_time[t,rd[1],tm] <= lastRoundPlayed[(g,rd,tm)]
|
|
else:
|
|
# print ("sync time", g, " " , displayGroups[g], " " , finalRoundDays)
|
|
for r in affectedRounds:
|
|
model2 += lpSum([lastRoundPlayed[(g,rd)] for rd in finalRoundDays if rd[0]==r ]) == 1
|
|
# model2 += lpSum([lastRoundPlayed[(g,rd)] for rd in finalRoundDays ]) == len(affectedRounds)
|
|
print (lpSum([lastRoundPlayed[(g,rd)] for rd in finalRoundDays ]) , " ==" , len(affectedRounds))
|
|
for t in displayGroups[g]:
|
|
for rd in finalRoundDays:
|
|
model2+= home[(t,rd[1])] + away[(t,rd[1])] <= lastRoundPlayed[(g,rd)]
|
|
# print ("home[(",t,rd[1],")] + away[(",t,rd[1],")] <= lastRoundPlayed[(",g,rd,")])")
|
|
|
|
|
|
if not evalRun:
|
|
# max length home stands /trips
|
|
for r in range (1,nRounds-thisSeason.maxTourLength+1):
|
|
# print (" at least one home and away in rounds ")
|
|
# for r3 in range(r,r+thisSeason.maxTourLength+1):
|
|
# print (r3 )
|
|
for t in teams:
|
|
if t not in noBreakLimitTeams:
|
|
# model2 += lpSum([homeInRound[t,r2] for r2 in range(r,r+thisSeason.maxTourLength+1)]) >=1
|
|
model2 += lpSum([awayInRound[t,r2] for r2 in range(r,r+thisSeason.maxTourLength+1)]) <=thisSeason.maxTourLength
|
|
model2 += lpSum([homeInRound[t,r2] for r2 in range(r,r+thisSeason.maxTourLength+1)]) <=thisSeason.maxTourLength
|
|
|
|
print ("check 1")
|
|
|
|
# blockings
|
|
for bl in blockings:
|
|
if getDayById[bl['day_id']]['round'] !=0:
|
|
if thisSeason.useFeatureKickOffTime and bl['time']!='----':
|
|
if bl['type'] in ["Home", "Hide"]:
|
|
model2+= blockingVio[bl['id']]== home_time[bl['team_id'], bl['day_id'],bl['time']]
|
|
# print ('FOUND HOME BLOCKING ', bl)
|
|
else:
|
|
model2+= blockingVio[bl['id']]== away_time[bl['team_id'], bl['day_id'],bl['time']]
|
|
# print ('FOUND AWAY BLOCKING ', bl)
|
|
else:
|
|
if bl['type'] in ["Home", "Hide"]:
|
|
model2+= blockingVio[bl['id']]== home[bl['team_id'], bl['day_id']]
|
|
# print ('FOUND HOME BLOCKING ', bl)
|
|
else:
|
|
model2+= blockingVio[bl['id']]== away[bl['team_id'], bl['day_id']]
|
|
# print ('FOUND AWAY BLOCKING ', bl)
|
|
|
|
|
|
print ("check 2")
|
|
|
|
hawOneVio={}
|
|
hawForOneNotViolated={}
|
|
|
|
def getStringFromSet(ss):
|
|
s2 =""
|
|
for s in ss:
|
|
s2+=str(s)+"_"
|
|
return s2[:-1]
|
|
|
|
# hawishes
|
|
for haw in hawishes:
|
|
print (haw['reason'])
|
|
for el in elemHaWishes[haw['id']]:
|
|
if thisSeason.useFeatureKickOffTime and len(hawTimes[haw['id']])>0:
|
|
if haw['homeAway']=='Home':
|
|
relGames = lpSum([home_time[t,d,tm] for d in elemHaWishDays[el] for t in elemHaWishTeams[el] for tm in hawTimes[haw['id']]])
|
|
# print (haw['id'] ," haw : ", relGames, hawTimes[haw['id']])
|
|
elif haw['homeAway']=='Away':
|
|
relGames = lpSum([away_time[t,d,tm] for d in elemHaWishDays[el] for t in elemHaWishTeams[el] for tm in hawTimes[haw['id']]])
|
|
else :
|
|
# print(haw,el)
|
|
relGames = lpSum([home_time[t,d,tm] + away_time[t,d,tm] for d in elemHaWishDays[el] for t in elemHaWishTeams[el] for tm in hawTimes[haw['id']]]) \
|
|
- lpSum([x_time[(t1,t2,rd,tm)] for d in elemHaWishDays[el] for rd in getRoundDaysByDay[d] for tm in hawTimes[haw['id']] for t1 in elemHaWishTeams[el] for t2 in elemHaWishTeams[el] if (t1,t2,rd,tm) in x_time.keys()])
|
|
|
|
else:
|
|
if haw['homeAway']=='Home':
|
|
relGames = lpSum([home[t,d] for d in elemHaWishDays[el] for t in elemHaWishTeams[el] ])
|
|
elif haw['homeAway']=='Away':
|
|
relGames = lpSum([away[t,d] for d in elemHaWishDays[el] for t in elemHaWishTeams[el] ])
|
|
else :
|
|
relGames = lpSum([home[t,d] + away[t,d] for d in elemHaWishDays[el] for t in elemHaWishTeams[el]]) - lpSum([x[t1,t2,rd] for d in elemHaWishDays[el] for rd in getRoundDaysByDay[d] for t1 in elemHaWishTeams[el] for t2 in elemHaWishTeams[el] if (t1,t2,rd) in x.keys() ])
|
|
if haw['minGames'] >0 :
|
|
model2+= relGames >= haw['minGames'] - HawVioTooLess[el]
|
|
# print ("adding min ha constraint")
|
|
if haw['maxGames'] >=0 :
|
|
model2+= relGames <= haw['maxGames'] + HawVioTooMuch[el]
|
|
# print ("adding max ha constraint")
|
|
|
|
|
|
usedConstraintNames = [""]
|
|
if haw['forOneDay']:
|
|
# print (haw['forOneDay'], hawDays[haw['id']])
|
|
# print ([el for el in elemHaWishes[haw['id']] ])
|
|
# for el in elemHaWishes[haw['id']] :
|
|
# print("- " , elemHaWishDays[el] , elemHaWishTeams[el] )
|
|
# print ([ (el, elemHaWishFirstDay[el]) for el in elemHaWishes[haw['id']] ])
|
|
relTeamString = { el : getStringFromSet(elemHaWishTeams[el]) for el in elemHaWishes[haw['id']] }
|
|
relTeams = set([ relTeamString[el] for el in elemHaWishes[haw['id']]])
|
|
# print (relTeams)
|
|
for rt in relTeams:
|
|
rtname = rt
|
|
if len(rt)>50 :
|
|
scname=""
|
|
while scname in usedConstraintNames:
|
|
ttt = bytes(rt+ ''.join(random.choice(string.ascii_lowercase) for i in range(10)), 'utf-8')
|
|
scname = hashlib.sha224(ttt).hexdigest()
|
|
rtname = scname[:10]
|
|
usedConstraintNames.append(rtname)
|
|
# print ("use rtname to encode wishes ", rtname)
|
|
|
|
hawOneVio[(haw['id'], rt)]= pulp.LpVariable('hawOneVio_'+str(haw['id'])+"_"+rtname, cat=pulp.LpContinuous)
|
|
for fd in hawDays[haw['id']]:
|
|
relWishes = [el for el in elemHaWishes[haw['id']] if elemHaWishFirstDay[el]== fd]
|
|
# relWishes = [el for el in elemHaWishes[haw['id']] ]
|
|
# print (" -" , relWishes , [elemHaWishDays[el] for el in relWishes])
|
|
hawForOneNotViolated[(haw['id'], rt, fd)]= 0
|
|
if len(relWishes)>0:
|
|
hawForOneNotViolated[(haw['id'], rt, fd)]= pulp.LpVariable('hawForOneViolated_'+str(haw['id'])+"_"+rtname+"_"+str(fd), cat=pulp.LpBinary)
|
|
model2 += lpSum( HawVioTooMuch[el]+HawVioTooLess[el] for el in relWishes if relTeamString[el]==rt) <= 1000 * (1-hawForOneNotViolated[(haw['id'],rt, fd)])
|
|
model2 += lpSum( hawForOneNotViolated[(haw['id'], rt, fd)] for fd in hawDays[haw['id']] ) >= haw['forOneDayNum']-hawOneVio[(haw['id'],rt)]
|
|
model2 += lpSum( hawOneVio[(haw['id'], rt)] for rt in relTeams ) == hawVio[haw['id']]
|
|
else:
|
|
# print (haw['forOneDay'], hawDays[haw['id']])
|
|
model2 += hawVio[haw['id']]== lpSum( HawVioTooMuch[el]+HawVioTooLess[el] for el in elemHaWishes[haw['id']])
|
|
|
|
|
|
if haw['prio']=="Hard" and "HardHAWishesNotBreakable" in special_wishes_active:
|
|
model2+= hawVio[haw['id']] ==0
|
|
print ("WISH HARD" ,haw['reason'])
|
|
|
|
|
|
# HawVioTotal=lpSum([prioVal[haw['prio']] * (HawVioTooLess[el]+HawVioTooMuch[el]) for haw in hawishes for el in elemHaWishes[haw['id']]])
|
|
# print (hawDays)
|
|
# print (elemHaWishFirstDay)
|
|
|
|
encOneVio={}
|
|
encForOneNotViolated={}
|
|
print ("check 3")
|
|
# encwishes
|
|
for enc in encwishes:
|
|
print (enc)
|
|
for el in elemEncWishes[enc['id']]:
|
|
# print (enc)
|
|
# model2+= encVio[enc['id']] == 1 - x[enc['team1_id'], enc['team2_id'], enc['day_id']]
|
|
|
|
if thisSeason.useFeatureKickOffTime and len(encTimes[enc['id']])>0:
|
|
if enc['minGames'] >0 :
|
|
model2+= encVioTooLess[el] >= enc['minGames'] - sum([ x_time[(t1,t2,rd, tm )] for d in elemEncWishDays[el] for rd in getRoundDaysByDay[d] for (t1,t2) in elemEncWishGames[el] for tm in encTimes[enc['id']] if (t1,t2) in games ])
|
|
if enc['maxGames'] >=0 :
|
|
# if enc['maxGames']==0:
|
|
print (enc['reason'], ' ', elemEncWishDays[el], ' ',enc['time'], ' ', encTeams1[enc['id']] , ' ',encTeams2[enc['id']] )
|
|
# print (sum([x_time[(t1,t2,rd, enc['time'])] for d in elemEncWishDays[el] for rd in getRoundDaysByDay[d] for (t1,t2) in elemEncWishGames[el] if (t1,t2) in games ]))
|
|
model2+= encVioTooMuch[el] >= -enc['maxGames'] + sum([x_time[(t1,t2,rd, tm )] for d in elemEncWishDays[el] for rd in getRoundDaysByDay[d] for (t1,t2) in elemEncWishGames[el] for tm in encTimes[enc['id']] if (t1,t2) in games ])
|
|
else:
|
|
if enc['minGames'] >0 :
|
|
model2+= encVioTooLess[el] >= enc['minGames'] - sum([ x[t1,t2,rd] for d in elemEncWishDays[el] for rd in getRoundDaysByDay[d] for (t1,t2) in elemEncWishGames[el] if (t1,t2) in games ])
|
|
if enc['maxGames'] >=0 :
|
|
# if enc['maxGames']==0:
|
|
# print (enc['reason'], ' ', encDays[enc['id']], ' ', encTeams1[enc['id']] , ' ',encTeams2[enc['id']] )
|
|
model2+= encVioTooMuch[el] >= -enc['maxGames'] + sum([ x[t1,t2,rd] for d in elemEncWishDays[el] for rd in getRoundDaysByDay[d] for (t1,t2) in elemEncWishGames[el] if (t1,t2) in games ])
|
|
|
|
if enc['forOneDay']:
|
|
for ed in encDaySets[enc['id']]:
|
|
if len(ed)>0:
|
|
relWishes = [ el for el in elemEncWishes[enc['id']] if elemEncWishDays[el] == ed ]
|
|
print ("###",ed, relWishes)
|
|
encForOneNotViolated[(enc['id'], ed[0])]= pulp.LpVariable('encForOneNotViolated_'+str(enc['id'])+"_"+str(ed[0]), cat=pulp.LpBinary)
|
|
model2 += sum( encVioTooMuch[el]+encVioTooLess[el] for el in relWishes) <= 1000 * (1-encForOneNotViolated[(enc['id'], ed[0])])
|
|
model2 += sum( encForOneNotViolated[(enc['id'], ed[0])] for ed in encDaySets[enc['id']] if len(ed)>0 ) >= enc['forOneDayNum']-encVio[enc['id']]
|
|
else:
|
|
model2 += encVio[enc['id']]== sum( encVioTooMuch[el]+encVioTooLess[el] for el in elemEncWishes[enc['id']])
|
|
|
|
|
|
if enc['prio']=="Hard" and "HardEncWishesNotBreakable" in special_wishes_active:
|
|
model2+= encVio[enc['id']] ==0
|
|
print ("WISH HARD" ,enc['reason'])
|
|
|
|
|
|
print ("check 4")
|
|
|
|
|
|
for cf in conferencewishes:
|
|
print (confTeams[cf['conference_id']])
|
|
model2 += lpSum([x[t1,t2, rd] for t1 in confTeams[cf['conference_id']] for t2 in confTeams[cf['conference_id']] for rd in getRoundDaysByDay[cf['day_id']] if (t1,t2, rd) in x.keys() ]) <= cf['maxGames'] + confVio[cf['id']]
|
|
model2 += lpSum([x[t1,t2, rd] for t1 in confTeams[cf['conference_id']] for t2 in confTeams[cf['conference_id']] for rd in getRoundDaysByDay[cf['day_id']] if (t1,t2, rd) in x.keys() ]) >= cf['minGames'] - confVio[cf['id']]
|
|
print (cf , " : " , confTeams[cf['conference_id']])
|
|
if thisSeason.groupBased:
|
|
model2+= confVio[cf['id']]==0
|
|
|
|
b_slots={(b.id,r) : [] for b in broadcastingwishes for r in rounds}
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for b in broadcastingwishes:
|
|
b_weekdays = [sl.weekday[:3] for sl in b.slots.all() ]
|
|
for r in rounds:
|
|
if len( [wd for wd in b_weekdays if wd in getWeekDaysPerRound[r]]) == len(b_weekdays):
|
|
b_slots[(b.id,r)] = [ (d,str(sl.timeslot.id),sl.quality) for sl in b.slots.all() for d in getDays[r] if getWeekDay[d]==sl.weekday[:3]]
|
|
if len(b_slots[(b.id,r)])>0:
|
|
model2 += lpSum([ x_time[g[0][0],g[0][1],(r,d),tm]+x_time[g[0][1],g[0][0],(r,d),tm] for g in topGames for (d,tm,q) in b_slots[(b.id,r)]]) >= b.minGames - broadVioTm[(b.id,r)]
|
|
model2 += lpSum([ x_time[t1,t2,(r,d),tm] for (t1,t2) in games for (d,tm,q) in b_slots[(b.id,r)]]) >= b.minGames - 0.5*broadVioTm[(b.id,r)]
|
|
if b.network.id in networkFavTeams.keys() :
|
|
model2 += lpSum([ x_time[t1,t2,(r,d),tm] for (t1,t2) in games for (d,tm,q) in b_slots[(b.id,r)] if t1 in networkFavTeams[b.network.id] or t2 in networkFavTeams[b.network.id] ]) >= b.minGames - 0.1*broadVioTm[(b.id,r)]
|
|
# if b.network.name== "Super Sport":
|
|
# print (" - " ,r , lpSum([ x_time[t1,t2,(r,d),tm] for (t1,t2) in games for (d,tm,q) in b_slots[(b.id,r)] if t1 in networkFavTeams[b.network.id] or t2 in networkFavTeams[b.network.id] ]))
|
|
|
|
# return ""
|
|
weekdayHomePref={}
|
|
dayHomePref={}
|
|
for t in teams:
|
|
tm = getTeamByName[getTeamById[t]]
|
|
weekdayHomePref[(t,'Mon')]=tm['home_pref_mo']
|
|
weekdayHomePref[(t,'Tue')]=tm['home_pref_tu']
|
|
weekdayHomePref[(t,'Wed')]=tm['home_pref_we']
|
|
weekdayHomePref[(t,'Thu')]=tm['home_pref_th']
|
|
weekdayHomePref[(t,'Fri')]=tm['home_pref_fr']
|
|
weekdayHomePref[(t,'Sat')]=tm['home_pref_sa']
|
|
weekdayHomePref[(t,'Sun')]=tm['home_pref_su']
|
|
for d in days :
|
|
dayHomePref[(t,d)]=weekdayHomePref[(t,getWeekDay[d])]
|
|
|
|
|
|
maxTravelDistance = max([ distanceById[t1,t2] for t1 in realteams for t2 in realteams ])
|
|
maxTravelDistance = max(1,maxTravelDistance)
|
|
|
|
singleTripWeight=50
|
|
breakImbalanceTotal= lpSum([ breakVioBalance[t] for t in realteams])
|
|
tripSavedTotal2= ( lpSum([ singleTripWeight *tripToSingleTripElement[(t,d,c)] for (t,d,c) in tripToSingleTripElement.keys() ])
|
|
+( lpSum([ c_weight[c] *tripToClusterSaving[(t,c)] *tripToCluster[(t,r,c)] for (t,r,c) in tripToCluster.keys() ])
|
|
+lpSum([ c_weight[c] *tripToClusterSaving[(t,c)] *tripToClusterDaily[(t,d,c)] for (t,d,c) in tripToClusterDaily.keys()]))/maxTravelDistance )
|
|
# HawVioTotal=lpSum([prioVal[haw['prio']] * (HawVioTooLess[el]+HawVioTooMuch[el]) for haw in hawishes for el in elemHaWishes[haw['id']]])
|
|
HawVioTotal=lpSum([prioVal[haw['prio']] * hawVio[haw['id']] for haw in hawishes])
|
|
encVioTotal=lpSum([prioVal[enc['prio']] * encVio[enc['id']] for enc in encwishes])
|
|
seedVioTotal=lpSum([100*prioVal[enc['prio']] * encVio[enc['id']] for enc in encwishes if enc['reason']=="Seed Game" ])
|
|
confVioTotal=lpSum([prioVal[conf['prio']] * confVio[conf['id']] for conf in conferencewishes])
|
|
# broadVioTotal=lpSum([ 10 * broadVio[d] for d in days]) + lpSum([ 10 * broadVioTm[b.id] for b in broadcastingwishes])
|
|
broadVioTotal=lpSum([ 10 * broadVioTm[(b.id,r)] for b in broadcastingwishes for r in rounds])
|
|
breakVioTotal=lpSum([prioVal[bl['prio']]*breakVio[(bl['id'],t)] for bl in breaks for t in realteams]) + 2*lpSum([prioVal[bl['prio']]*breakVio[(bl['id'],t)] for bl in breaks for t in importantteams])
|
|
break3VioTotal=lpSum([2*break3InRound[t,r] for t in teams for r in rounds])
|
|
tooManyTop4InRowTotal=lpSum([ 10*tooManyTop4InRow[(t,r)] for t in teams for r in rounds])
|
|
pairingVioTotal=lpSum([ 5 *prioVal[pair['prio']] * pairingVio[(pair['id'],d)] for pair in pairings for d in days+higherLeagueDayIds])
|
|
# blockingVioTotal=lpSum([ 100 * blockingVio[bl['id']] for bl in blockings if bl['type']=="Home"])
|
|
# print (blockings)
|
|
# for bl in blockings:
|
|
# if bl['type'] in ["Home"]:
|
|
# print (blocked_arena[(bl["team_id"],bl["day_id"],"----")], getTeamById[bl["team_id"]], getNiceDay[bl["day_id"]] , bl )
|
|
|
|
fulfBlocks =set([(bl["team_id"], getRoundByDay[bl["day_id"]]) for bl in blockings if bl['type'] in ["Home"] and blocked_arena[(bl["team_id"],bl["day_id"],"----")]] )
|
|
|
|
blockingVioTotal2=lpSum([ -30 * homeInRound[tr] for tr in fulfBlocks if thisSeason.allowBlockingViosInImprove and runMode=='Improve'] )
|
|
blockingVioTotal=lpSum([ 100 * blockingVio[bl['id']] for bl in blockings if bl['type'] in ["Home", "Hide"]]) +blockingVioTotal2
|
|
|
|
travelVioTotal=lpSum([ 100 * blockingVio[bl['id']] for bl in blockings if bl['type']=="Away"])
|
|
gamesTooCloseTotal=lpSum([ 120 * gamesTooClose[(t,d)] for t in teams for d in days+higherLeagueDayIds if conflictDays[(t,d)]]) + lpSum([ 120 * gamesTooClose2[(t,r)] for t in teams for r in rounds ])
|
|
derbiesMissingTotal=lpSum([ 30 * derbyMissing[d] for d in days])
|
|
tooManyHomesInStadiumTotal=lpSum([ 110 * tooManyHomesInStadium[(stadium, d)] for stadium in stadiums for d in days+higherLeagueDayIds])
|
|
unpreferredTotal=lpSum([ home[t, d] for t in teams for d in days if dayHomePref[(t,d)]==0 ])
|
|
# competitionVioTotal=lpSum([ 100 * competitionVio[(c,d,t)] for (c,d,t) in competitions])
|
|
competitionVioTotal=lpSum([ 100 * (home[t,d]+ away[t,d]) for (t,d) in competitions.keys()])
|
|
fixedGameVioTotal=lpSum([ 10000 * fixedGameVio[(t1,t2,d)] for (t1,t2,d) in fixedGames]) + lpSum([ 10000 * fixedGame2Vio[(t1,t2,d)] for (t1,t2,d) in fixedGames2])
|
|
missingGamesVioTotal=lpSum([ 2000000 * missingGamesVio[(t1,t2)] for (t1,t2) in realgames])
|
|
# TODO - UNDO CHANGES: missingGamesVioTotal=lpSum([ 2000 * missingGamesVio[(t1,t2)] for (t1,t2) in games])
|
|
oldScenGamesTotal=lpSum([ wg * x[t1,t2,rd] for (t1,t2,r,wg) in otherScenGames for rd in getRoundDaysByRound[r]] )
|
|
totalAttendance=lpSum([ attendance[(t1,t2,d)] * x[t1,t2,(r,d)] for (t1,t2) in games for (r,d) in roundDays ] )
|
|
|
|
specialObjectives = 0
|
|
specialWishItems ={ sw:[] for sw in special_wishes_active}
|
|
specialWishVio ={}
|
|
|
|
|
|
optCameraMovement = "Standard"
|
|
if thisLeague.name in ["Indian Super League"] and thisSeason.name != "2021":
|
|
optCameraMovement = "TV-Kits"
|
|
if thisLeague.name in ["Indian Premier League"]:
|
|
optCameraMovement = "Stadiums"
|
|
|
|
# tvkitproblem = {}
|
|
move2 = {}
|
|
newtrip2 = {}
|
|
if optCameraMovement == "TV-Kits":
|
|
networkIds=networkName.keys()
|
|
TV_day_pairs = [ (d1, d2) for d1 in days for d2 in days if getDateTimeDay[d1]+datetime.timedelta(days=1)<getDateTimeDay[d2] and getDateTimeDay[d1]>=getDateTimeDay[d2] -datetime.timedelta(days=20) ]
|
|
movements = [ (t1,d1,t2,d2) for t1 in realteams for t2 in realteams for (d1,d2) in TV_day_pairs if getDateTimeDay[d2]-getDateTimeDay[d1] >= datetime.timedelta(days=distanceInDaysById[(t1,t2)]+1 ) ]
|
|
|
|
pred2 ={ (t,d) :[] for t in realteams for d in days }
|
|
succ2 ={ (t,d) :[] for t in realteams for d in days }
|
|
move2 = { (t1,d1,t2,d2) : pulp.LpVariable('move2_'+str(t1)+'_'+str(d1)+'_'+str(t2)+'_'+str(d2), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for (t1,d1,t2,d2) in movements }
|
|
unserved_tv = { (t1,d1) : pulp.LpVariable('unserved_tv'+str(t1)+'_'+str(d1), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in realteams for d1 in days }
|
|
newtrip2 = { (t1,d1) : pulp.LpVariable('newtrip2_'+str(t1)+'_'+str(d1), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in realteams for d1 in days }
|
|
tooManyTrips2 = pulp.LpVariable('tooManyTrips2', lowBound = 0, cat = pulp.LpContinuous)
|
|
|
|
for (t1,d1,t2,d2) in movements:
|
|
# print (getTeamById[t1] , getTeamById[t2] , distanceById[t1,t2] , distanceInDaysById[t1,t2] , getNiceDay[d1] , getNiceDay[d2] )
|
|
pred2[(t2,d2)].append( (t1,d1,t2,d2))
|
|
succ2[(t1,d1)].append( (t1,d1,t2,d2))
|
|
|
|
# if thisLeague.name in ["Indian Super League"]:
|
|
# for (t,d) in newtrip2.keys():
|
|
# # model2+= home[(t,d)] == lpSum( movement[tdtd] for tdtd in pred2[(t,d)] )
|
|
# model2+= home[(t,d)] >= lpSum( move2[tdtd] for tdtd in succ2[(t,d)] )
|
|
# model2+= home[(t,d)] == lpSum( move2[tdtd] for tdtd in pred2[(t,d)] ) + newtrip2 [(t,d)] + unserved_tv[(t,d)]
|
|
# model2+= lpSum( move2[tdtd] for tdtd in move2.keys() if tdtd[0] == t and tdtd[1] == d) <= 1 - unserved_tv[(t,d)]
|
|
# model2+= lpSum( unserved_tv[k] for k in unserved_tv.keys()) <= 1
|
|
# model2+= tooManyTrips2 <= 0
|
|
# else:
|
|
for (t,d) in newtrip2.keys():
|
|
# model2+= home[(t,d)] == lpSum( movement[tdtd] for tdtd in pred2[(t,d)] )
|
|
model2+= home[(t,d)] >= lpSum( move2[tdtd] for tdtd in succ2[(t,d)] )
|
|
model2+= home[(t,d)] == lpSum( move2[tdtd] for tdtd in pred2[(t,d)] ) + newtrip2 [(t,d)]
|
|
model2+= home[(t,d)] == lpSum( newtrip2[td] for td in newtrip2.keys()) <= len(networkIds) + tooManyTrips2
|
|
|
|
# model2+= home[(t,d)] <= lpSum(home[(t2,d2)] for t2 in realteams for d2 in otherDays if getDateTimeDay[d2]<=getDateTimeDay[d]- datetime.timedelta(days=distanceInDaysById[(t,t2)]) ) +tvkitproblem[(t,d)]
|
|
specialObjectives += 0.01*lpSum( distanceById[t1,t2]*move2[(t1,d1,t2,d2)] for (t1,d1,t2,d2) in movements)+ 5000* tooManyTrips2
|
|
|
|
jamshedpurVio={}
|
|
if thisLeague.name in ["Indian Super League"]:
|
|
jamshedpur = getTeamByName["Jamshedpur FC"]['id']
|
|
print ("Jamshedpur FC" , jamshedpur)
|
|
jamshedpurVio = { d1 : pulp.LpVariable('jamshedpurVio_'+str(d1), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for d1 in days }
|
|
for d in days:
|
|
fourdays = [d2 for d2 in days if getDateTimeDay[d2]>=getDateTimeDay[d] and getDateTimeDay[d2]<=getDateTimeDay[d]+datetime.timedelta(days=3) ]
|
|
otherday = [d2 for d2 in fourdays if getDateTimeDay[d2]==getDateTimeDay[d]+datetime.timedelta(days=3) ]
|
|
if len(otherday)>0:
|
|
otherday=otherday[0]
|
|
print (getNiceDay[d], fourdays , getNiceDay[otherday] )
|
|
for t in realteams:
|
|
if t!=jamshedpur:
|
|
# model2+= lpSum( x[jamshedpur,t, rd] for d2 in fourdays for rd in getRoundDaysByDay[d2] ) + lpSum( home[t,d2] + away[t,d2] for d2 in fourdays ) <= 2 + jamshedpurVio[d]
|
|
model2+= lpSum( x[jamshedpur,t, rd] for rd in getRoundDaysByDay[d] ) + home[t,otherday] + away[t,otherday] <= 1 + jamshedpurVio[d]
|
|
model2+= lpSum( x[jamshedpur,t, rd] for rd in getRoundDaysByDay[otherday] ) + home[t,d] + away[t,d] <= 1 + jamshedpurVio[d]
|
|
else:
|
|
model2+= home[t,d] + away[t,otherday] <= 1 + jamshedpurVio[d]
|
|
model2+= away[t,d] + home[t,otherday] <= 1 + jamshedpurVio[d]
|
|
|
|
specialObjectives += 1000*lpSum( jamshedpurVio[d] for d in days)
|
|
|
|
|
|
|
|
|
|
if "AlwaysEnoughRestDays" in special_wishes_active:
|
|
model2+=lpSum([ gamesTooClose[(t,d)] for t in teams for d in days if conflictDays[(t,d)]]) ==0
|
|
|
|
if "NoPairingVio" in special_wishes_active:
|
|
# model2+=pairingVioTotal==0
|
|
hardpairs = [ p for p in pairings if p['prio']=="Hard" ]
|
|
if len(hardpairs)>0:
|
|
model2+=lpSum([ pairingVio[(pair['id'],d)] for pair in pairings for d in days+higherLeagueDayIds if pair['prio']=="Hard"])==0
|
|
|
|
if "NoBreaks" in special_wishes_active:
|
|
model2+=breakVioTotal==0
|
|
|
|
if "SyncDaysInGroups" in special_wishes_active:
|
|
for (t1,t2) in games:
|
|
for d in days:
|
|
model2+= home[(t1,d)]+away[(t1,d)] == home[(t2,d)]+away[(t2,d)]
|
|
|
|
if "austrianSymmetry" in special_wishes_active:
|
|
for (t1,t2) in games:
|
|
if (t2,t1) in games:
|
|
for (r1,r2) in [(1,7),(2,8),(3,9),(4,10),(5,6)] :
|
|
model2+= lpSum([x[t1,t2, rd] for rd in getRoundDaysByRound[r1]]) == lpSum([x[t2,t1, rd] for rd in getRoundDaysByRound[r2]])
|
|
|
|
|
|
# if "3RestDaysBetweenMD2andMD3" in special_wishes_active:
|
|
# print ("3RestDaysBetweenMD2andMD3")
|
|
# sw_type="3RestDaysBetweenMD2andMD3"
|
|
# # for (r2,d2) in getRoundDaysByRound[2] :
|
|
# # for (r3,d3) in getRoundDaysByRound[3]
|
|
# # print (getDateTimeDay[d2],getDateTimeDay[d3])
|
|
# dpairs = [(d2, d3) for (r2,d2) in getRoundDaysByRound[2] for (r3,d3) in getRoundDaysByRound[3] if getDateTimeDay[d3]-getDateTimeDay[d2]== datetime.timedelta(days=sw_int1[sw_type]+1) ]
|
|
# for (d2,d3) in dpairs:
|
|
# for t in realteams:
|
|
# model2 += home[(t,d2)]+away[(t,d2)]==home[(t,d3)] +away[(t,d3)]
|
|
# print (getDateTimeDay[d2],getDateTimeDay[d3])
|
|
#
|
|
|
|
print (special_wishes_active)
|
|
|
|
|
|
if thisLeague.name in ["Indian Premier League"]:
|
|
|
|
networkIds=networkName.keys()
|
|
networkIdByName = { networkName[nw] : nw for nw in networkName.keys() }
|
|
|
|
z = {(t1,t2,(r,d),nw) : pulp.LpVariable('playsInPune_'+str(t1)+'_'+str(t2)+'_'+str(r)+'_'+str(d)+'_'+str(nw), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for (t1,t2,(r,d)) in x.keys() for nw in networkIds }
|
|
|
|
playInStadium = {(t,r,nw) : lpSum([z[t,t2,rd,nw]+z[t2,t,rd,nw] for t2 in opponents[t] for rd in getRoundDaysByRound[r]]) for t in realteams for r in rounds for nw in networkIds }
|
|
|
|
for (t1,t2,(r,d)) in x.keys() :
|
|
model2+=lpSum([z[t1,t2,(r,d),nw] for nw in networkIds ])== x[(t1,t2,(r,d))]
|
|
|
|
for nw in networkIds:
|
|
maxGamesInStadium = 3 if networkName[nw] in ["Brabourne", "MCA Stadium, Pune"] else 4
|
|
print ("MAX GAMES PER TEAM IN ", networkName[nw] , " ", maxGamesInStadium)
|
|
|
|
for r in rounds:
|
|
model2+= lpSum(playInStadium[(t,r,nw)] for t in realteams ) <= 2
|
|
|
|
if r<=nRounds-2:
|
|
model2+= lpSum(playInStadium[(t,r2,nw)] for t in realteams for r2 in [r,r+1,r+2]) <= 4
|
|
|
|
for t in realteams:
|
|
model2+= lpSum(playInStadium[(t,r,nw)] for r in rounds) == maxGamesInStadium
|
|
|
|
|
|
fix3s= [("CSK", "KKR", "2022-03-26", "Wankhede"),
|
|
("MI", "DC", "2022-03-27", "Brabourne"),
|
|
("PBKS", "RCB", "2022-03-27", "DY Patil"),
|
|
("GT", "LSG", "2022-03-28", "Wankhede"),
|
|
("RR", "SRH", "2022-03-29", "MCA Stadium, Pune"),
|
|
]
|
|
if "ipl_only_first_game_fixed" in special_wishes_active:
|
|
fix3s= [("CSK", "KKR", "2022-03-26", "Wankhede")]
|
|
|
|
for (t1, t2, dt, std) in fix3s:
|
|
if t1 in getTeamIdByShortName.keys() and t2 in getTeamIdByShortName.keys() and parse(dt) in getDayByDateTime.keys() and std in networkIdByName.keys():
|
|
t11 = getTeamIdByShortName[t1]
|
|
t12 = getTeamIdByShortName[t2]
|
|
nwid = networkIdByName[std]
|
|
model2+= lpSum( [z[t11,t12,rd,nwid] + z[t12,t11,rd,nwid] for rd in getRoundDaysByDay[getDayByDateTime[parse(dt)]] ] )==1
|
|
print ("fixing" , (t1, t2, dt, std) )
|
|
|
|
# puneTrip = {(t,r) : pulp.LpVariable('puneTrip_'+str(t)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t in realteams for r in rounds }
|
|
puneTrip = {(t,r) : pulp.LpVariable('puneTrip_'+str(t)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t in realteams for r in rounds }
|
|
noPuneTrip = {t : pulp.LpVariable('noPuneTrip_'+str(t), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t in realteams }
|
|
|
|
puneStadiumId = networkIdByName["MCA Stadium, Pune"]
|
|
|
|
# Matches at the Pune venue need to be finished by 15th May.
|
|
model2+= lpSum([ playInStadium[(t,r,puneStadiumId)] for t in realteams for r in rounds if r>51 ]) ==0
|
|
|
|
# for (t1,t2) in games:
|
|
# for rd in roundDays:
|
|
# z[(t1,t2,rd,puneStadiumId)].cat=pulp.LpInteger
|
|
|
|
|
|
if "specialTripsToPune" in special_wishes_active:
|
|
sw_type="specialTripsToPune"
|
|
for t in realteams:
|
|
for r in rounds:
|
|
if r<=nRounds-2:
|
|
model2+= puneTrip[t,r] <= playInStadium[t, r, puneStadiumId ]
|
|
if r == nRounds-2:
|
|
model2+= puneTrip[t,r] <= playInStadium[t, r+2, puneStadiumId ]
|
|
if r == nRounds-3:
|
|
model2+= puneTrip[t,r] <= playInStadium[t, r+2, puneStadiumId ] + playInStadium[t, r+3, puneStadiumId ]
|
|
if r < nRounds-3:
|
|
model2+= puneTrip[t,r] <= playInStadium[t, r+2, puneStadiumId ] + playInStadium[t, r+3, puneStadiumId ] + playInStadium[t, r+4, puneStadiumId ]
|
|
|
|
model2+= lpSum( [puneTrip[t,r] for r in rounds ] ) >= 1 - noPuneTrip[t]
|
|
model2+= puneTrip[t,nRounds-1] ==0
|
|
model2+= puneTrip[t,nRounds] ==0
|
|
|
|
specialObjectives += -20* sw_prio[sw_type]*lpSum([puneTrip[tr] for tr in puneTrip.keys()]) + 40* sw_prio[sw_type]*lpSum([noPuneTrip[t] for t in realteams])
|
|
|
|
if "no_b2b_in_pune" in special_wishes_active:
|
|
sw_type="no_b2b_in_pune"
|
|
for r in rounds:
|
|
if r<nRounds:
|
|
specialWishItems[sw_type].append(r)
|
|
specialWishVio[(sw_type,r)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(r), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= lpSum( [z[t1,t2,rd,puneStadiumId] for (t1,t2) in games for rd in getRoundDaysByRound[r]+getRoundDaysByRound[r+1]] ) <=1+specialWishVio[(sw_type,r)]
|
|
|
|
specialObjectives += 20*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,r)] for r in specialWishItems[sw_type] ])
|
|
|
|
if "minHomeAttractivity" in special_wishes_active:
|
|
# showAttractivity = min([d.attractivity for d in days]) < max([d.attractivity for d in days])
|
|
sw_type="minHomeAttractivity"
|
|
for t in realteams:
|
|
specialWishItems[sw_type].append((t))
|
|
specialWishVio[(sw_type,t)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t), lowBound=0, cat=pulp.LpContinuous)
|
|
model2 += sum([ home[t,d]*getDayById[d]['attractivity'] for d in days ]) >= sw_int1[sw_type] - specialWishVio[(sw_type,t)]
|
|
specialObjectives += lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t)] for t in realteams ])
|
|
|
|
if "alwaysFixedRestDaysWhenPossible" in special_wishes_active:
|
|
print ("alwaysFixedRestDaysWhenPossible")
|
|
sw_type="alwaysFixedRestDaysWhenPossible"
|
|
dpairs=[]
|
|
for r in rounds:
|
|
if r<nRounds:
|
|
dpairs += [(d2, d3) for (r2,d2) in getRoundDaysByRound[r] for (r3,d3) in getRoundDaysByRound[r+1] if getDateTimeDay[d3]-getDateTimeDay[d2]== datetime.timedelta(days=sw_int1[sw_type]+1) ]
|
|
for (d2,d3) in dpairs:
|
|
print ("found days " , getNiceDay[d2], getNiceDay[d3], )
|
|
for t in realteams:
|
|
specialWishItems[sw_type].append((t,d2))
|
|
specialWishVio[(sw_type,t,d2)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d2), lowBound=0, cat=pulp.LpContinuous)
|
|
model2 += home[(t,d2)]+away[(t,d2)] <= home[(t,d3)] +away[(t,d3)] + specialWishVio[(sw_type,t,d2)]
|
|
model2 += home[(t,d3)]+away[(t,d3)] <= home[(t,d2)] +away[(t,d2)] + specialWishVio[(sw_type,t,d2)]
|
|
# print (getDateTimeDay[d2],getDateTimeDay[d3])
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
|
|
|
|
if "RecoverBeforeDistantGame" in special_wishes_active:
|
|
sw_type="RecoverBeforeDistantGame"
|
|
distantTeams = { t: [ t2 for t2 in realteams if distanceById[t,t2]> sw_int1[sw_type] and t2!=t] for t in realteams }
|
|
for d in days:
|
|
nextDays = [ d2 for d2 in days if getDateTimeDay[d]<getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=sw_int2[sw_type]) ]
|
|
# print (d, nextDays )
|
|
if len(nextDays)>0:
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
# print ("\n",getTeamById[t], ":", [ (getTeamById[t2] , distanceById[t,t2]) for t2 in distantTeams[t] ])
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= home[(t,d)] + lpSum([ x[t1,t,rd] for t1 in distantTeams[t] for d2 in nextDays for rd in getRoundDaysByDay[d2] ]) <= 1 + specialWishVio[(sw_type,t,d)]
|
|
# print ("GAMES :", sum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]))
|
|
# print ("HOMES :", sum([ home[(t,d2)] for d2 in nextDays]))
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
|
|
if "RecoverAfterDistantGame" in special_wishes_active:
|
|
sw_type="RecoverAfterDistantGame"
|
|
distantTeams = { t: [ t2 for t2 in realteams if distanceById[t,t2]> sw_int1[sw_type] and t2!=t] for t in realteams }
|
|
for d in days:
|
|
nextDays = [ d2 for d2 in days if getDateTimeDay[d]<getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=sw_int2[sw_type]) ]
|
|
# print (d, nextDays )
|
|
# if len(nextDays)>0 and (thisSeason.league.name != "ICE Hockey League" or getWeekDay[d]=="Fri" ):
|
|
if len(nextDays)>0:
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
# print ("\n",getTeamById[t], ":", [ (getTeamById[t2] , distanceById[t,t2]) for t2 in distantTeams[t] ])
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= lpSum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]) + lpSum([ home[(t,d2)] for d2 in nextDays]) <= 1 + specialWishVio[(sw_type,t,d)]
|
|
# print ("GAMES :", sum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]))
|
|
# print ("HOMES :", sum([ home[(t,d2)] for d2 in nextDays]))
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
|
|
if "RecoverAfterDistantGame2" in special_wishes_active:
|
|
sw_type="RecoverAfterDistantGame2"
|
|
distantTeams = { t: [ t2 for t2 in realteams if distanceById[t,t2]> sw_int1[sw_type] and t2!=t] for t in realteams }
|
|
for d in days:
|
|
nextDays = [ d2 for d2 in days if getDateTimeDay[d]<getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=sw_int2[sw_type]) ]
|
|
# print (d, nextDays )
|
|
# if len(nextDays)>0 and (thisSeason.league.name != "ICE Hockey League" or getWeekDay[d]=="Fri" ):
|
|
if len(nextDays)>0:
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
# print ("\n",getTeamById[t], ":", [ (getTeamById[t2] , distanceById[t,t2]) for t2 in distantTeams[t] ])
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= lpSum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]) + lpSum([ home[(t,d2)] for d2 in nextDays]) <= 1 + specialWishVio[(sw_type,t,d)]
|
|
# print ("GAMES :", sum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]))
|
|
# print ("HOMES :", sum([ home[(t,d2)] for d2 in nextDays]))
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
|
|
if "NoSingleDistantGame" in special_wishes_active:
|
|
sw_type="NoSingleDistantGame"
|
|
distantTeams = { t: [ t2 for t2 in realteams if distanceById[t,t2]> sw_int1[sw_type] and t2!=t] for t in realteams }
|
|
for d in days:
|
|
otherDays = [ d2 for d2 in days if d!=d2 and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=sw_int2[sw_type]-1) and getDateTimeDay[d]-getDateTimeDay[d2]<= datetime.timedelta(days=sw_int2[sw_type]-1) ]
|
|
if len(otherDays)>0:
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= lpSum([ x[t1,t,rd] for t1 in distantTeams[t] for rd in getRoundDaysByDay[d] ]) - lpSum([ x[t1,t,rd] for t1 in distantTeams[t] for d2 in otherDays for rd in getRoundDaysByDay[d2] ]) <= specialWishVio[(sw_type,t,d)]
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
# # print (specialObjectives)
|
|
|
|
|
|
|
|
if "RestDaysAfterLateGame" in special_wishes_active:
|
|
sw_type="RestDaysAfterLateGame"
|
|
for d in days:
|
|
nextDays = [ d2 for d2 in days if getDateTimeDay[d]<getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=sw_int1[sw_type]) ]
|
|
# print (d, nextDays )
|
|
if len(nextDays)>0:
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
model2+= home_time[(t,d,getIdByTime["Late"])]+away_time[(t,d,getIdByTime["Late"])] + lpSum([ home[(t,d2)]+away[(t,d2)] for d2 in nextDays]) <= 1 + specialWishVio[(sw_type,t,d)]
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
# print (specialObjectives)
|
|
|
|
|
|
if "playWeekendsCompletelyHomeOrAway" in special_wishes_active:
|
|
sw_type="playWeekendsCompletelyHomeOrAway"
|
|
weekendDays = [d for d in days if getWeekDay[d] in ["Fri"]]
|
|
specialHomeAwayOnWeekend={}
|
|
for d in weekendDays:
|
|
nextDays = [ d2 for d2 in days if getDateTimeDay[d]<getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<= datetime.timedelta(days=2) ]
|
|
specialWishItems[sw_type]+=[(t,d) for t in realteams]
|
|
for t in realteams:
|
|
specialWishVio[(sw_type,t,d)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
for ha in ["Home", "Away"] :
|
|
specialHomeAwayOnWeekend[(t,d,ha)]= pulp.LpVariable('specialHomeAwayOnWeekend_'+ha+'_'+str(t)+"_"+str(d), lowBound=0, cat=pulp.LpContinuous)
|
|
for d2 in [d]+nextDays:
|
|
model2+= home[(t,d2)] <= specialHomeAwayOnWeekend[(t,d,"Home")]
|
|
model2+= away[(t,d2)] <= specialHomeAwayOnWeekend[(t,d,"Away")]
|
|
model2+= specialHomeAwayOnWeekend[(t,d,"Home")]+specialHomeAwayOnWeekend[(t,d,"Away")]<=1+specialWishVio[(sw_type,t,d)]
|
|
specialObjectives += 10*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t,d)] for (t,d) in specialWishItems[sw_type] ])
|
|
|
|
if "alternateHAforSameEncounters" in special_wishes_active:
|
|
sw_type="alternateHAforSameEncounters"
|
|
for p in phases:
|
|
if p>0:
|
|
relrd =[ rd for d in getDaysOfPhase[p-1]+getDaysOfPhase[p] for rd in getRoundDaysByDay[d]]
|
|
for (t1,t2) in games:
|
|
model2+= lpSum( x[(t1,t2,rd)] for rd in relrd ) <= 1
|
|
|
|
standardObjectives=1+gew['Home-/Away']*HawVioTotal\
|
|
+gew['Home-/Away']*3*unpreferredTotal \
|
|
+gew['Pairings']*pairingVioTotal \
|
|
+gew['Blockings']*blockingVioTotal \
|
|
+gew['Traveling']*travelVioTotal \
|
|
+gew['Blockings']*gamesTooCloseTotal \
|
|
-5*gew['Trips']*tripSavedTotal2 \
|
|
+gew['Breaks']*breakVioTotal \
|
|
+gew['Breaks']*2*break3VioTotal \
|
|
+gew['Breaks']*1*breakImbalanceTotal \
|
|
+5*gew['Encounters']*encVioTotal \
|
|
+5*gew['Encounters']*seedVioTotal \
|
|
+gew['Conferences']*confVioTotal \
|
|
+gew['Blockings']*tooManyHomesInStadiumTotal \
|
|
+gew['Broadcasting']*broadVioTotal \
|
|
+gew['Derbies']*derbiesMissingTotal \
|
|
+5*competitionVioTotal \
|
|
+1.0*tooManyTop4InRowTotal\
|
|
+fixedGameVioTotal\
|
|
+missingGamesVioTotal\
|
|
+oldScenGamesTotal\
|
|
-0.01*totalAttendance
|
|
|
|
if sharedStadiums:
|
|
standardObjectives+= lpSum ( prio_weight[p] * useStadiumTimeSlot[(t,d,s)] for (t,d) in t_site_bestTimeSlots.keys() for (p,s) in t_site_bestTimeSlots[(t,d)]) \
|
|
+100000* lpSum([ nonIceGame[(t,d)] for (t,d) in nonIceGame.keys()])
|
|
|
|
|
|
model2+= standardObjectives
|
|
|
|
# model2+= fixedGameVioTotal +missingGamesVioTotal
|
|
# model2+= fixedGameVioTotal
|
|
# print ("TESTING")
|
|
# for ttr in x.keys():
|
|
# makeIntVar(x[ttr])
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=40,msg=1))
|
|
# print ("TESTING DONE")
|
|
|
|
|
|
global_coeff = {t['id'] : int(t['attractivity']) for t in teamObjects }
|
|
domestic_coeff = {t['id'] : int(0.1+10*(t['attractivity']-int(t['attractivity']))) for t in teamObjects }
|
|
|
|
def quality_of_game(t1, t2):
|
|
return global_coeff[t1]*global_coeff[t2]
|
|
|
|
def quality_of_game_dom(t1, t2):
|
|
return domestic_coeff[t1]*global_coeff[t2]
|
|
|
|
|
|
print ("Broadcasting " , gew['Broadcasting'])
|
|
|
|
if thisSeason.useFeatureBackToBack:
|
|
critical_day_pairs = [ (d1,d2) for r in [r1 for r1 in rounds if r1>1] for d1 in getDays[r-1] for d2 in getDays[r] if getDateTimeDay[d2]-getDateTimeDay[d1]==datetime.timedelta(days=1) ]
|
|
nextCritical ={ d1 : False for d1 in days}
|
|
for (d1,d2) in critical_day_pairs:
|
|
nextCritical[d1]=d2
|
|
|
|
badBackToBack= { (t,d1) : pulp.LpVariable('badBackToBack_'+str(t)+"_"+str(d1) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for (d1,d2) in critical_day_pairs }
|
|
back2backBlocks = []
|
|
color_weight = { "Y" : 0.003 , "R" : 0.05 , "X" : 1.0 , }
|
|
|
|
|
|
show_TV_markets = False
|
|
|
|
# START SPECIAL CONSTRAINTS
|
|
|
|
# hat leider nicht geklappt :
|
|
# specialOpt = False
|
|
# optFileName = "optimize_" + thisSeason.league.name.replace(' ', '_')
|
|
# if path.exists("scheduler/"+optFileName+".py"):
|
|
# specialOpt = import_module('scheduler.'+optFileName)
|
|
|
|
# if specialOpt:
|
|
# specialOpt.enhanceModel2(model2)
|
|
# with open("scheduler/"+optFileName+".py") as f: exec(f.read())
|
|
|
|
if mathModelName=="NHL":
|
|
startDoubleGame= { (t1,t2,r) : pulp.LpVariable('startDoubleGame'+str(t1)+"_"+str(t2)+"_"+str(r) , lowBound = 0, cat = pulp.LpContinuous) for (t1,t2) in games for r in rounds if r<nRounds }
|
|
|
|
bad_travels = [ (t1,t2,"X") for t1 in realteams for t2 in realteams if distanceById[t1,t2]>1300]
|
|
# print (bad_travels)
|
|
# for (t1,t2,c) in bad_travels:
|
|
# print (getTeamById[t1] , " - " , getTeamById[t2])
|
|
|
|
# print(thisSeason.name[-3:])
|
|
|
|
thisCountry =""
|
|
for t in realteams:
|
|
thisCountry=t_country[t]
|
|
# print (getTeamById[t], t_country[t] , t_conference[t])
|
|
# print (thisCountry)
|
|
|
|
for (t1,t2,r) in startDoubleGame.keys():
|
|
model2 += startDoubleGame[(t1,t2,r)] <= x_round[(t1,t2,r)]
|
|
model2 += startDoubleGame[(t1,t2,r)] <= x_round[(t1,t2,r+1)]
|
|
|
|
specialObjectives+= -100* lpSum( [ startDoubleGame[ttr] for ttr in startDoubleGame.keys()])
|
|
|
|
if thisCountry=="United States":
|
|
for (t1,t2) in games:
|
|
for r in rounds:
|
|
if r>=3:
|
|
model2 += x_round[(t1,t2,r-2)]+x_round[(t1,t2,r-1)]+x_round[(t1,t2,r)]<=2
|
|
# print ("no 3 in row " , t1, t2, r-2 , r)
|
|
|
|
bad_travels = [ (t1,t2,"X") for t1 in realteams for t2 in realteams if distanceById[t1,t2]>1300 and t_conference[t1]==t_conference[t2]]
|
|
# print (len(bad_travels))
|
|
# for (t1,t2,c) in bad_travels:
|
|
# print (getTeamById[t1] , " - " , getTeamById[t2])
|
|
|
|
back2backBlocks += [ ([t1],[t2],1.0) for (t1,t2,c) in bad_travels]
|
|
|
|
contractable=True
|
|
while contractable:
|
|
contractable=False
|
|
for ((tms1_a,tms2_a,w_a),(tms1_b,tms2_b,w_b)) in [ (b1,b2) for b1 in back2backBlocks for b2 in back2backBlocks if b1!=b2 and b1[2]==b2[2] and t_conference[b1[0][0]]==t_conference[b2[0][0]] ]:
|
|
if min([ distanceById[t1,t2] for t1 in tms1_a for t2 in tms2_b]) > 1300 and min([ distanceById[t1,t2] for t1 in tms1_b for t2 in tms2_a]) > 1300 :
|
|
# print ("unify ", b1,b2)
|
|
back2backBlocks.remove((tms1_a,tms2_a,w_a))
|
|
back2backBlocks.remove((tms1_b,tms2_b,w_b))
|
|
back2backBlocks.append((list(set(tms1_a+tms1_b)), list(set(tms2_a+tms2_b)), w_a))
|
|
contractable=True
|
|
break;
|
|
|
|
# print (len(back2backBlocks)," back2backBlocks")
|
|
# for (tms1,tms2,w) in back2backBlocks:
|
|
# print ("")
|
|
# print (tms1,tms2,w)
|
|
# for t1 in set(tms1):
|
|
# print ("from ", getTeamById[t1])
|
|
# for t2 in set(tms2):
|
|
# print ("to ", getTeamById[t2])
|
|
# print (len(bad_travels), "bad_travels")
|
|
# print (len(back2backBlocks),"back2backBlocks")
|
|
|
|
else:
|
|
# startDoubleGame
|
|
for r in rounds:
|
|
if r>=5:
|
|
for (t1,t2) in games:
|
|
if gameCntr[(t2,t1)]>0 :
|
|
model2 += lpSum(x_round[(t1,t2,r2)] + x_round[(t2,t1,r2)] for r2 in [r-4,r-3,r-2,r-1,r])<=3
|
|
else:
|
|
model2 += lpSum(x_round[(t1,t2,r2)] for r2 in [r-4,r-3,r-2,r-1,r])<=3
|
|
# if r>2 and r <10:
|
|
# model2 += x_round[(t1,t2,r-1)] <= x_round[(t1,t2,r-2)] + x_round[(t1,t2,r)]
|
|
|
|
if r>=9:
|
|
for t1 in teams :
|
|
model2 += lpSum(homeInRound[(t1,r2)] for r2 in rounds if r2>=r-8 and r2<=r)>=1
|
|
model2 += lpSum(awayInRound[(t1,r2)] for r2 in rounds if r2>=r-8 and r2<=r)>=1
|
|
|
|
east_teams = [ t for t in realteams if t_lon[t]>= -87]
|
|
center_teams = [ t for t in realteams if -87 > t_lon[t] and t_lon[t]>=-100 ]
|
|
west_teams = [ t for t in realteams if t_lon[t]< -113]
|
|
back2backBlocks += [ (east_teams, center_teams+west_teams,1.0), (center_teams+west_teams,east_teams,1.0) ]
|
|
|
|
|
|
if mathModelName=="Champions Hockey League":
|
|
toTime={(c,d) : ["n/a"] for c in countries for d in days}
|
|
for d in days:
|
|
for (c,tms) in [ ("SWE", ["18:05/19:05","20:35"]), ("FIN",["19:00"]),
|
|
("CZE",["17:00 or 17:30", "19:30 or 20:00"]), ("SVK",["17:00 or 17:30", "19:30 or 20:00"]),
|
|
("HUN" , ["19:00"]),
|
|
("AUT",["20:20"]),
|
|
("SUI",["19:45"]),
|
|
("GER",["18:00"]),
|
|
("NOR",["18:00"]),
|
|
("DEN",["18:00"]),
|
|
("POL",["18:00"]),
|
|
("SLO",["19:15"]),
|
|
("FRA",["20:00"]),
|
|
("SCO",["20:00 or 20:30"]),
|
|
]:
|
|
toTime[(c,d)]=tms
|
|
|
|
for (cntries,nds,tms) in [
|
|
(["SWE"],["2022-09-03","2022-09-04"],["14:35","15:05"]),
|
|
(["CZE","SVK"],["2022-09-03","2022-09-04"],["16:00","18:30"]),
|
|
(["CZE","SVK"],["2022-09-10"],["15:00 or 16:00","17:30 or 18:30"]),
|
|
(["CZE","SVK"],["2022-09-11",],["15:00 or 16:00","18:30"]),
|
|
(["HUN"],["2022-09-03","2022-09-04","2022-09-10","2022-09-11"],["18:00"]),
|
|
(["AUT"],["2022-09-02"],["19:30"]),(["AUT"],["2022-09-09"],["18:00"]),
|
|
(["SUI"],["2022-09-01"],["20:00"]),
|
|
(["SUI"],["2022-09-03","2022-09-10"],["14:30/15:00"]),
|
|
(["SUI"],["2022-09-04","2022-09-11"],["16:30"]),
|
|
(["GER"],["2022-09-01","2022-09-02",],["20:15"]),
|
|
(["GER"],["2022-09-03","2022-09-10",],["17:00"]),
|
|
(["GER"],["2022-09-04",],["15:00 or 19:00"]),
|
|
(["GER"],["2022-09-08",],["19:00","20:00"]),
|
|
(["GER"],["2022-09-09",],["16:45"]),
|
|
(["GER"],["2022-09-11",],["?"]),
|
|
(["NOR"],["2022-09-08"],["no pref."]),
|
|
(["NOR"],["2022-10-04","2022-10-05","2022-10-10","2022-10-11",],["18:30"]),
|
|
(["DEN"],["2022-09-02","2022-09-09",],["19:30"]),
|
|
(["DEN"],["2022-09-08"],["no pref."]),
|
|
(["SLO"],["2022-09-08"],["20:00"]),
|
|
(["SLO"],["2022-09-03"],["18:00"]),
|
|
(["SLO"],["2022-09-04"],["17:30"]),
|
|
(["SLO"],["2022-09-08","2022-09-09",],["18:00 or 20:00"]),
|
|
(["SLO"],["2022-09-10","2022-09-11",],["18:00"]),
|
|
] :
|
|
if getNiceDayRaw[d] in nds:
|
|
for c in cntries:
|
|
toTime[(c,d)]=tms
|
|
else:
|
|
print (getNiceDayRaw[d], nds, getNiceDayRaw[d] in nds)
|
|
|
|
show_TV_markets = True
|
|
critical_day_pairs_CHL = [ (d1,d2) for d1 in set(getDays[1]+getDays[3]) for d2 in set(getDays[2]+getDays[4]) if getDateTimeDay[d2]-getDateTimeDay[d1]==datetime.timedelta(days=2) ]
|
|
|
|
# confusingDays = [ d for d in getDays[1]+getDays[2] if d in getDays[3]+getDays[4]]
|
|
# for (t1,t2) in games:
|
|
# print (getTeamById[t1], " " ,getTeamById[t2], lpSum([ x[(t1,t2,rd)] for r2 in [1,2,3] for rd in getRoundDaysByRound[r2]]) )
|
|
# model2+= lpSum([ x[(t1,t2,rd)] + x[(t2,t1,rd)] for r2 in [1,2,3] for rd in getRoundDaysByRound[r2]]) <= 1
|
|
# model2+= lpSum([ x[(t1,t2,rd)] + x[(t2,t1,rd)] for r2 in [4,5,6] for rd in getRoundDaysByRound[r2]]) <= 1
|
|
|
|
# for d in confusingDays:
|
|
# rnds = [1,2] if t_pot[t]!=5 else [3,4]
|
|
# for r2 in rnds:
|
|
# if (r2,d) in roundDays:
|
|
# setUB(x[(t1,t2,(r2,d))],0)
|
|
# # print ("forbidding " ,r2 ,d, " on day " , getNiceDay[d])
|
|
|
|
|
|
for t in teams :
|
|
# model2+= lpSum([ home[(t,d1)] + away[t,d1] for d1 in confusingDays ]) == 2
|
|
for (d1,d2) in critical_day_pairs_CHL:
|
|
model2 += home[(t,d1)]==home[(t,d2)]
|
|
model2 += away[(t,d1)]==away[(t,d2)]
|
|
# model2 += homeInRound[(t1,1)] == homeInRound[(t1,2)]
|
|
|
|
|
|
if mathModelName=="Florida State League":
|
|
notEnoughHomes= { t : pulp.LpVariable('notEnoughHomes_'+str(t) , lowBound = 0, cat = pulp.LpContinuous) for t in teams }
|
|
notEnoughAways= { t : pulp.LpVariable('notEnoughAways_'+str(t) , lowBound = 0, cat = pulp.LpContinuous) for t in teams }
|
|
for t in teams:
|
|
# model2+= lpSum( [ homeInRound[t,r] for r in rounds]) >= 20
|
|
model2+= lpSum( [ home[t,d] for d in days]) >= 70 - notEnoughHomes[t]
|
|
model2+= lpSum( [ away[t,d] for d in days]) >= 70 - notEnoughAways[t]
|
|
model2+= lpSum( [ home[t,d] for d in days]) <= 70 + notEnoughHomes[t]
|
|
model2+= lpSum( [ away[t,d] for d in days]) <= 70 + notEnoughAways[t]
|
|
# print ("doing special stuff ", thisSeason.gamesPerRound=="one day")
|
|
|
|
|
|
getConference={}
|
|
for c in confTeams.keys():
|
|
if len(confTeams[c])>2:
|
|
for t in confTeams[c]:
|
|
getConference[t]=c
|
|
|
|
visited_unbalanced_MINLB= {(t1,t2) : pulp.LpVariable('visited_too_less_'+str(t1)+'_'+str(t2), lowBound = 0, cat = pulp.LpContinuous) for (t1,t2) in games }
|
|
for (t1,t2) in games:
|
|
# print (t1 , t2, getRoundDaysByRound[1][0], distance[getTeamById[t1],getTeamById[t2]] , getConference[t1]==getConference[t2] )
|
|
model2+= lpSum([x[(t1,t2,getRoundDaysByRound[r][0])] for r in rounds]) >=1
|
|
model2+= lpSum([x[(t1,t2,getRoundDaysByRound[r][0])] for r in rounds]) >=2- visited_unbalanced_MINLB[(t1,t2)]
|
|
model2+= lpSum([x[(t1,t2,getRoundDaysByRound[r][0])] for r in rounds]) <=3+ visited_unbalanced_MINLB[(t1,t2)]
|
|
# exit(0)
|
|
|
|
# model2+= x[(13859,13860,(1, 26627))] >=1
|
|
|
|
# for r in rounds:
|
|
# print (r, getRoundDaysByRound[r] , len(getRoundDaysByRound[r]))
|
|
|
|
# visited_too_less_MINLB= { (t1,t2) : not_visited * x[(t1,t2,getRoundDaysByRound[r][0])] for (t1,t2) in games }
|
|
travelCost_Driving_MINLB= { (t1,t2,r) : distance[getTeamById[t1],getTeamById[t2]] * x[(t1,t2,getRoundDaysByRound[r][0])] for (t1,t2) in games for r in rounds }
|
|
travelCost_Hotel_MINLB = { (t1,t2,r) : len(getRoundDaysByRound[r]) * (getConference[t1]!=getConference[t2]) * x[(t1,t2,getRoundDaysByRound[r][0])] for (t1,t2) in games for r in rounds }
|
|
|
|
travelCost_Total_MINLB = lpSum([0.001*travelCost_Driving_MINLB[(t1,t2,r)]+0.2*travelCost_Hotel_MINLB[(t1,t2,r)] for (t1,t2) in games for r in rounds])
|
|
|
|
total_visited_unbalanced_MINLB = lpSum([visited_unbalanced_MINLB[(t1,t2)] for (t1,t2) in games])
|
|
|
|
notEnoughGames_MINLB = lpSum([notEnoughHomes[t] + notEnoughAways[t] for t in teams])
|
|
|
|
# specialObjectives+=travelCost_Total_MINLB+10*visited_too_less_MINLB
|
|
specialObjectives+=100*( 0.1*travelCost_Total_MINLB+0.2*total_visited_unbalanced_MINLB+2*notEnoughGames_MINLB)
|
|
|
|
|
|
if mathModelName in ["ALPS" ,"ICE Hockey League" , "ICEYSL"]:
|
|
|
|
if mathModelName != "ALPS" and False:
|
|
firstTwoPhases= [ (r,d) for (r,d) in roundDays if r<=26 ]
|
|
secondTwoPhases= [ (r,d) for (r,d) in roundDays if r>= 27 ]
|
|
for (t1,t2) in games:
|
|
# print (t1 , t2, getRoundDaysByRound[1][0], distance[getTeamById[t1],getTeamById[t2]] , getConference[t1]==getConference[t2] )
|
|
for rrr in [firstTwoPhases, secondTwoPhases]:
|
|
model2+= lpSum([x[(t1,t2,rd)] for rd in rrr]) <=1
|
|
|
|
# trips_ICE_raw={
|
|
# 'DEC': [['AVS', 'VIC'],[ 'ZNO', 'BWL'],[ 'IBC', 'G99', 'KAC'],['VSV', 'HKO']],
|
|
# 'AVS': [['DEC', 'HCI', 'HCB', 'PUS', 'RBS']],
|
|
# 'HCB': [['ZNO', 'VIC'],['IBC', 'AVS']],
|
|
# 'G99': [['HCB', 'PUS', 'DEC', 'HCI']],
|
|
# 'BWL': [['HCB', 'PUS', 'DEC']],
|
|
# 'ZNO': [['HCB', 'PUS' 'DEC', 'HCI']],
|
|
# 'VSV': [['HCB', 'PUS'],[ 'DEC', 'HCI'],[ 'VIC', 'AVS'],[ 'VIC', 'IBC', 'ZNO']],
|
|
# 'KAC': [['PUS', 'HCB'],[ 'HCI', 'DEC']],
|
|
# 'RBS': [],
|
|
# 'VIC': [['HCB', 'PUS'],['DEC', 'HCI']],
|
|
# 'HCI': [['VIC', 'AVS'],[ 'BWL', 'ZNO'],[ 'BWL', 'IBC'],[ 'VSV', 'KAC', 'HKO']],
|
|
# 'IBC': [['HCB', 'PUS'],[ 'DEC', 'HCI'],[ 'HKO', 'VSV']],
|
|
# 'HKO': [['HCB', 'PUS'],[ 'DEC', 'HCI']],
|
|
# 'PUS': []}
|
|
|
|
|
|
# trips_ICE_raw={
|
|
# 'DEC': [['BWL', 'IBC' , 'AVS' , 'ZNO' , 'VIC' ],[ 'IBC', 'G99', 'KAC'],['VSV', 'HKO']],
|
|
# 'AVS': [['DEC', 'HCI', 'HCB', 'PUS', 'RBS']],
|
|
# 'HCB': [['BWL', 'IBC' , 'AVS' , 'ZNO' , 'VIC' ]],
|
|
# 'G99': [['HCB', 'PUS', 'DEC', 'HCI']],
|
|
# 'BWL': [['HCB', 'PUS', 'DEC']],
|
|
# 'ZNO': [['HCB', 'PUS','DEC', 'HCI']],
|
|
# 'VSV': [['HCB', 'PUS', 'DEC', 'HCI'],[ 'VIC', 'AVS', 'VIC', 'IBC', 'ZNO']],
|
|
# 'KAC': [['PUS', 'HCB', 'HCI', 'DEC']],
|
|
# 'RBS': [],
|
|
# 'VIC': [['HCB', 'PUS','DEC', 'HCI']],
|
|
# 'HCI': [['BWL', 'IBC' , 'AVS' , 'ZNO' , 'VIC' ],[ 'VSV', 'KAC', 'HKO']],
|
|
# 'IBC': [['HCB', 'PUS', 'DEC', 'HCI'],[ 'HKO', 'VSV']],
|
|
# 'HKO': [['HCB', 'PUS', 'DEC', 'HCI']],
|
|
# 'PUS': [['BWL', 'IBC' , 'AVS' , 'ZNO' , 'VIC' ]]}
|
|
|
|
|
|
trips_ICE_raw={
|
|
'DEC': [['AVS', 'VIC'],['IBC', 'ZNO'],['G99', 'HKO']],
|
|
'AVS': [['DEC', 'HCI'],['HCB', 'PUS']],
|
|
'HCB': [['AVS', 'VIC'],['IBC', 'ZNO']],
|
|
'G99': [],
|
|
'BWL': [],
|
|
'ZNO': [['DEC', 'HCI'],['HCB', 'PUS']],
|
|
'VSV': [],
|
|
'KAC': [],
|
|
'RBS': [],
|
|
'VIC': [['DEC', 'HCI'],['HCB', 'PUS']],
|
|
'HCI': [['AVS', 'VIC'],['IBC', 'ZNO']],
|
|
'IBC': [['DEC', 'HCI'],['HCB', 'PUS']],
|
|
'HKO': [],
|
|
'PUS': [['AVS', 'VIC'],['IBC', 'ZNO']]}
|
|
|
|
# importantTravellers = [getTeamIdByShortName[ts2] for ts2 in [ "AVS", "HCB", "DEC", "PUS", "IBC" , "HCI" ] ]
|
|
# importantTravellers = [getTeamIdByShortName[ts2] for ts2 in [ "AVS", "HCB", "DEC", "PUS", "IBC" , "HCI" , "VIC" ] ]
|
|
|
|
firstRoundOfChristmas=30
|
|
lastRoundOfChristmas=36
|
|
badweekdayGames=0
|
|
|
|
if mathModelName == "ALPS" :
|
|
trips_ICE_raw={
|
|
'EHC': [['JES', 'KFT'],['VCS', 'SWL']],
|
|
'ECB': [['JES', 'KFT'],['VCS', 'SWL']],
|
|
'VEU': [['JES', 'KFT'],['VCS', 'SWL']],
|
|
'VCS': [['ECB', 'EHC'],['VEU', 'KEC'],['ASH', 'SGC', 'RIT', 'GHE', 'WSV', 'FAS', 'HCM']],
|
|
'JES': [['ECB', 'EHC'], ['VEU', 'KEC']],
|
|
'KFT': [['ECB', 'EHC'], ['VEU', 'KEC']],
|
|
'ASH': [['VCS', 'SWL']],
|
|
'SGC': [['VCS', 'SWL']],
|
|
'RIT': [['VCS', 'SWL']],
|
|
'GHE': [['VCS', 'SWL']],
|
|
'WSV': [['VCS', 'SWL']],
|
|
'FAS': [['VCS', 'SWL']],
|
|
'HCM': [['VCS', 'SWL']]
|
|
}
|
|
badweekdayGames = lpSum([ distanceById[t1,t2]* distanceById[t1,t2] * distanceById[t1,t2] /8000000 * x[t1,t2,(r,d)] for (t1,t2) in games for (r,d) in roundDays if getWeekDay[d]=="Thu" and distanceById[t1,t2]>250 ])
|
|
firstRoundOfChristmas=25
|
|
lastRoundOfChristmas=29
|
|
firstRoundOfChristmas=27
|
|
lastRoundOfChristmas=28
|
|
|
|
importantTravellers = [getTeamIdByShortName[ts2] for ts2 in [ "EHC", "ECB", "VEU", "VCS", "JES", "KFT", "ASH", "SGC", "RIT", "GHE", "WSV", "FAS", "HCM" ] ]
|
|
|
|
if mathModelName == "ICE Hockey League" :
|
|
importantTravellers = [getTeamIdByShortName[ts2] for ts2 in ["HCB", "AVS", "DEC", "PUS", "IBC" , "ZNO" , "HCI" , "VIC"] ]
|
|
importantTravellers = [getTeamIdByShortName[ts2] for ts2 in [ "DEC", "AVS", "HCB", "VIC", "HCI", "IBC", "PUS"] ]
|
|
|
|
|
|
if mathModelName == "ICEYSL" :
|
|
trips_ICE_raw={ t_shortname[t] : [] for t in teams }
|
|
trips_ICE_raw["HCI"] = [['NHA', 'VSV'],['IHC', 'OHE'], ['EAS', 'EAO']]
|
|
importantTravellers = [getTeamIdByShortName[ts2] for ts2 in ["HCI"] ]
|
|
badweekdayGames = lpSum([(x[t1,t2,(r,d)]) for (t1,t2) in games for (r,d) in roundDays if getWeekDay[d] in [ "Wed", "Thu" ] and distanceById[t1,t2]>200 ])
|
|
|
|
short_dist = { t : sorted([ (distanceById[t,t2] ,t2) for t2 in teams if t2!=t ]) for t in teams }
|
|
maxDist4 = { t : max(210, short_dist[t][3][0]) for t in teams }
|
|
|
|
# for t in teams :
|
|
# print (getTeamById[t] , maxDist4[t], short_dist[t])
|
|
# for ds,t2 in short_dist[t]:
|
|
# print (" - " , getTeamById[t2] , ds)
|
|
|
|
|
|
toofarForXmas = [ (t1,t2,(r,d)) for (t1,t2) in games for (r,d) in roundDays if r>= firstRoundOfChristmas and (r<=lastRoundOfChristmas or r>=51 ) and distanceById[t1,t2]> maxDist4[t2]+1 ]
|
|
wayToofarForXmas = [ (t1,t2,(r,d)) for (t1,t2) in games for (r,d) in roundDays if r>= firstRoundOfChristmas and r<=lastRoundOfChristmas and distanceById[t1,t2]> 300 ]
|
|
|
|
# kac dec feh sind wichtig
|
|
# vci 2 trips hcidec pusboz
|
|
|
|
cntr = 0
|
|
trips_ICE = {}
|
|
for ts in trips_ICE_raw.keys():
|
|
t= getTeamIdByShortName[ts]
|
|
for tp in trips_ICE_raw[ts]:
|
|
tps = [getTeamIdByShortName[ts2] for ts2 in tp]
|
|
trips_ICE[cntr]=(t,tps)
|
|
# print (trips_ICE)
|
|
print ("TRIP", cntr, tp, tps)
|
|
cntr+=1
|
|
# for t2 in tps:
|
|
# print (" - " , getTeamById [t2] , " " , distanceById[t,t2] , "km")
|
|
print ()
|
|
|
|
print (trips_ICE)
|
|
|
|
important_trips_ICE = [ cn for cn in trips_ICE.keys() if trips_ICE[cn][0] in importantTravellers ]
|
|
trips_ICE_by_traveller ={t: [ cn for cn in trips_ICE.keys() if trips_ICE[cn][0] == t ] for t in teams }
|
|
print (trips_ICE_by_traveller)
|
|
|
|
|
|
day1pairs =[ (d1,d2) for d1 in days for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] ==datetime.timedelta(days=1) and getRoundByDay[d1] != getRoundByDay[d2] ]
|
|
|
|
toughWeekend_ICE = { (t,d1,d2) : pulp.LpVariable('toughWeekend_ICE_'+str(t)+'_'+str(d1) , lowBound = 0, cat = pulp.LpContinuous) for t in realteams for (d1,d2) in day1pairs }
|
|
|
|
for d1,d2 in day1pairs:
|
|
print (getNiceDay[d1], getNiceDay[d2])
|
|
for t in realteams:
|
|
print (t,d1,d2 , getTeamById[t], getNiceDay[d1],getNiceDay[d2])
|
|
model2+= home[(t,d1)] + lpSum([x[(t1,t,rd)] for t1 in teams for rd in getRoundDaysByDay[d2] if distanceById[t,t1]>150] ) <=1+toughWeekend_ICE[t,d1,d2]
|
|
model2+= home[(t,d2)] + lpSum([x[(t1,t,rd)] for t1 in teams for rd in getRoundDaysByDay[d1] if distanceById[t,t1]>150] ) <=1+toughWeekend_ICE[t,d1,d2]
|
|
|
|
traveling_ICE = { (tr,d1,d2) : pulp.LpVariable('traveling_ICE_'+str(tr)+'_'+str(d1) , lowBound = 0, cat = pulp.LpContinuous) for tr in trips_ICE.keys() for (d1,d2) in day1pairs }
|
|
notEnoughTravel = { t : pulp.LpVariable('important_travel_'+str(t) , lowBound = 0, cat = pulp.LpContinuous) for t in importantTravellers }
|
|
|
|
for (tr,d1,d2) in traveling_ICE.keys():
|
|
t2,tms = trips_ICE[tr]
|
|
model2+= traveling_ICE[(tr,d1,d2)] <= lpSum([x[(t1,t2,rd)] for t1 in tms for rd in getRoundDaysByDay[d1]])
|
|
# if t2 in [getTeamIdByShortName["DEC"] ,getTeamIdByShortName["HCB"]] and nextDay[d2]!=-1:
|
|
if t2 in [] and nextDay[d2]!=-1:
|
|
model2+= traveling_ICE[(tr,d1,d2)] <= lpSum([x[(t1,t2,rd)] for t1 in tms for rd in getRoundDaysByDay[d2]+getRoundDaysByDay[nextDay[d2]]])
|
|
else:
|
|
model2+= traveling_ICE[(tr,d1,d2)] <= lpSum([x[(t1,t2,rd)] for t1 in tms for rd in getRoundDaysByDay[d2]])
|
|
|
|
if mathModelName == "ALPS":
|
|
for t in realteams:
|
|
for d1,d2 in day1pairs:
|
|
model2+= away[(t,d1)] <= lpSum([ traveling_ICE[(tr,d1,d2)] for tr in trips_ICE_by_traveller[t] ]) + toughWeekend_ICE[t,d1,d2]
|
|
print ( "away ",t , getTeamById[t] , " only if travelling ", getNiceDay[d1] , d2)
|
|
|
|
for t in importantTravellers:
|
|
model2+= lpSum([ traveling_ICE[(tr,d1,d2)] for tr in trips_ICE_by_traveller[t] for (d1,d2) in day1pairs]) >=2 - notEnoughTravel[t]
|
|
|
|
notEnoughTravelTotal = lpSum([ notEnoughTravel[t] for t in notEnoughTravel.keys() ])
|
|
badXmas = lpSum([ 0.01*distanceById[t1,t2] *x[(t1,t2,rd)] for (t1,t2,rd) in toofarForXmas ]) + 10 * lpSum([ x[ttrd] for ttrd in wayToofarForXmas ])
|
|
toughWeekends = lpSum([ toughWeekend_ICE[tdd] for tdd in toughWeekend_ICE.keys() ])
|
|
|
|
# specialObjectives += 0.2* gew['Trips'] * (-100* lpSum([traveling_ICE[tdd] for tdd in traveling_ICE.keys()]) - 300 * lpSum([traveling_ICE[(tr,d1,d2)] for (tr,d1,d2) in traveling_ICE.keys() if tr in important_trips_ICE ])) + 100*badXmas + 1000 *toughWeekends
|
|
specialObjectives += ( 0.2* gew['Trips'] * (
|
|
-0 * lpSum([traveling_ICE[tdd] for tdd in traveling_ICE.keys()])
|
|
- 400 * lpSum([traveling_ICE[(tr,d1,d2)] for (tr,d1,d2) in traveling_ICE.keys() if tr in important_trips_ICE ])
|
|
)
|
|
+ 100 * badXmas
|
|
+ 1000 * toughWeekends
|
|
+ 1000*notEnoughTravelTotal
|
|
# + 50*badweekdayGames
|
|
+ 200*badweekdayGames
|
|
)
|
|
|
|
for (t,r,c) in tripToCluster.keys():
|
|
model2 += tripToCluster[(t,r,c)] == 0
|
|
|
|
|
|
if mathModelName=="NBA":
|
|
|
|
for (t1,t2,d,channel) in seedTV:
|
|
if previousDay[d]!=-1:
|
|
model2 +=lpSum([ x_time[(t3,t4,rd,getIdByTime["Late"])] for (t3,t4) in games for rd in getRoundDaysByDay[previousDay[d]] if t1 in [t3,t4] ])+ lpSum([ x_time[(t1,t2,rd,getIdByTime["Early"])] for rd in getRoundDaysByDay[d]]) <=1
|
|
model2 +=lpSum([ x_time[(t3,t4,rd,getIdByTime["Late"])] for (t3,t4) in games for rd in getRoundDaysByDay[previousDay[d]] if t2 in [t3,t4] ])+ lpSum([ x_time[(t1,t2,rd,getIdByTime["Early"])] for rd in getRoundDaysByDay[d]]) <=1
|
|
if nextDay[d]!=-1:
|
|
model2 +=lpSum([ x_time[(t3,t4,rd,getIdByTime["Early"])] for (t3,t4) in games for rd in getRoundDaysByDay[nextDay[d]] if t1 in [t3,t4] ])+ lpSum([ x_time[(t1,t2,rd,getIdByTime["Late"])] for rd in getRoundDaysByDay[d]]) <=1
|
|
model2 +=lpSum([ x_time[(t3,t4,rd,getIdByTime["Early"])] for (t3,t4) in games for rd in getRoundDaysByDay[nextDay[d]] if t2 in [t3,t4] ])+ lpSum([ x_time[(t1,t2,rd,getIdByTime["Late"])] for rd in getRoundDaysByDay[d]]) <=1
|
|
|
|
badRepeater= { (t,r) : pulp.LpVariable('badRepeater_'+str(t)+"_"+str(r) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for r in rounds }
|
|
tooLongTrip_NBA= { (t,r) : pulp.LpVariable('tooLongTrip_NBA_'+str(t)+"_"+str(r) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for r in rounds }
|
|
eastWestTrip_NBA= { (t,r) : pulp.LpVariable('eastWestTrip_NBA_'+str(t)+"_"+str(r) , lowBound = 0, cat = pulp.LpContinuous) for t in teams for r in rounds }
|
|
|
|
if nRounds >= 100:
|
|
for t in realteams:
|
|
if r>=3:
|
|
model2 += break3InRound[(t,r)] +2>= lpSum([ homeInRound[(t,r2)] + awayInRound[(t,r2)] for r2 in [r-2,r-1,r]])
|
|
|
|
userepeater= False
|
|
if userepeater:
|
|
for t in realteams:
|
|
print ("building repeater contraints for " , t)
|
|
for r in rounds:
|
|
# forbid same opponents on successive days
|
|
for t2 in realteams:
|
|
if t<t2 and r>2:
|
|
model2 += lpSum([ (x[(t,t2,rd )]+x[(t2,t,rd)]) for rd in getRoundDaysByRound[r-2]+getRoundDaysByRound[r-1]+getRoundDaysByRound[r] ]) <= 1 + badRepeater[(t,r)]
|
|
# badRepeater[(t,r)].upBound=0
|
|
if r>4:
|
|
model2 += lpSum([ home [(t,d )] for (r2,d) in roundDays if r2>=r-4 and r2<=r ]) >= 1 - tooLongTrip_NBA[(t,r)]
|
|
model2 += lpSum([ away [(t,d )] for (r2,d) in roundDays if r2>=r-4 and r2<=r ]) >= 1 - tooLongTrip_NBA[(t,r)]
|
|
|
|
b2bmatrix = {"BOS": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "R", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"TOR": {"BOS": "Y", "TOR": "G", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "Y", "CHA": "Y", "ATL": "Y", "ORL": "R", "MIA": "R", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "R", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"NYK": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "R", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"BKN": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "R", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"PHI": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "G", "MEM": "Y", "NOP": "Y", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "Y", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"WAS": {"BOS": "G", "TOR": "Y", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "Y", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"CHA": {"BOS": "G", "TOR": "Y", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "Y", "DAL": "Y", "SAS": "Y", "OKC": "Y", "MIN": "Y", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"ATL": {"BOS": "Y", "TOR": "Y", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "Y", "OKC": "G", "MIN": "Y", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"ORL": {"BOS": "Y", "TOR": "R", "NYK": "Y", "BKN": "Y", "PHI": "Y", "WAS": "Y", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "Y", "CLE": "Y", "IND": "G", "CHI": "R", "MIL": "R", "MEM": "Y", "NOP": "G", "HOU": "Y", "DAL": "Y", "SAS": "Y", "OKC": "Y", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"MIA": {"BOS": "Y", "TOR": "R", "NYK": "Y", "BKN": "Y", "PHI": "Y", "WAS": "Y", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "Y", "CLE": "Y", "IND": "Y", "CHI": "R", "MIL": "R", "MEM": "Y", "NOP": "G", "HOU": "Y", "DAL": "Y", "SAS": "Y", "OKC": "R", "MIN": "R", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"DET": {"BOS": "G", "TOR": "G", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "R", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "Y", "NOP": "R", "HOU": "R", "DAL": "R", "SAS": "R", "OKC": "Y", "MIN": "G", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"CLE": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "Y", "HOU": "R", "DAL": "Y", "SAS": "R", "OKC": "Y", "MIN": "G", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"IND": {"BOS": "Y", "TOR": "Y", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "Y", "HOU": "Y", "DAL": "Y", "SAS": "Y", "OKC": "G", "MIN": "G", "DEN": "X", "UTA": "X", "PHX": "X", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"CHI": {"BOS": "G", "TOR": "G", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "Y", "DAL": "G", "SAS": "Y", "OKC": "G", "MIN": "G", "DEN": "R", "UTA": "R", "PHX": "R", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"MIL": {"BOS": "G", "TOR": "G", "NYK": "G", "BKN": "G", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "Y", "DAL": "G", "SAS": "Y", "OKC": "G", "MIN": "G", "DEN": "Y", "UTA": "R", "PHX": "R", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"MEM": {"BOS": "Y", "TOR": "Y", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "G", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "G", "DEN": "Y", "UTA": "R", "PHX": "R", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"NOP": {"BOS": "R", "TOR": "R", "NYK": "R", "BKN": "R", "PHI": "Y", "WAS": "Y", "CHA": "G", "ATL": "G", "ORL": "G", "MIA": "G", "DET": "G", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "Y", "DEN": "R", "UTA": "R", "PHX": "R", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"HOU": {"BOS": "R", "TOR": "R", "NYK": "R", "BKN": "R", "PHI": "R", "WAS": "R", "CHA": "Y", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "Y", "CLE": "Y", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "Y", "DEN": "R", "UTA": "R", "PHX": "Y", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"DAL": {"BOS": "R", "TOR": "R", "NYK": "R", "BKN": "R", "PHI": "R", "WAS": "R", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "Y", "CLE": "G", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "Y", "DEN": "Y", "UTA": "Y", "PHX": "Y", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"SAS": {"BOS": "R", "TOR": "R", "NYK": "R", "BKN": "R", "PHI": "R", "WAS": "R", "CHA": "Y", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "R", "CLE": "Y", "IND": "G", "CHI": "Y", "MIL": "Y", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "Y", "DEN": "Y", "UTA": "Y", "PHX": "Y", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"OKC": {"BOS": "R", "TOR": "R", "NYK": "R", "BKN": "R", "PHI": "R", "WAS": "R", "CHA": "G", "ATL": "G", "ORL": "Y", "MIA": "Y", "DET": "G", "CLE": "Y", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "G", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "G", "DEN": "G", "UTA": "Y", "PHX": "Y", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"MIN": {"BOS": "Y", "TOR": "Y", "NYK": "Y", "BKN": "Y", "PHI": "G", "WAS": "Y", "CHA": "G", "ATL": "G", "ORL": "R", "MIA": "R", "DET": "G", "CLE": "G", "IND": "G", "CHI": "G", "MIL": "G", "MEM": "G", "NOP": "Y", "HOU": "Y", "DAL": "G", "SAS": "Y", "OKC": "G", "MIN": "G", "DEN": "Y", "UTA": "Y", "PHX": "R", "LAC": "X", "LAL": "X", "GSW": "X", "SAC": "X", "POR": "X"},
|
|
"DEN": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "Y", "MIL": "G", "MEM": "Y", "NOP": "Y", "HOU": "G", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "G", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "R", "LAL": "R", "GSW": "Y", "SAC": "Y", "POR": "R"},
|
|
"UTA": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "R", "MIL": "Y", "MEM": "Y", "NOP": "R", "HOU": "Y", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "G", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "G"},
|
|
"PHX": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "R", "MIL": "R", "MEM": "R", "NOP": "R", "HOU": "Y", "DAL": "G", "SAS": "G", "OKC": "G", "MIN": "Y", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "Y"},
|
|
"LAC": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "X", "MIL": "X", "MEM": "X", "NOP": "X", "HOU": "X", "DAL": "X", "SAS": "X", "OKC": "X", "MIN": "X", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "G"},
|
|
"LAL": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "X", "MIL": "X", "MEM": "X", "NOP": "X", "HOU": "X", "DAL": "X", "SAS": "X", "OKC": "X", "MIN": "X", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "G"},
|
|
"GSW": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "X", "MIL": "X", "MEM": "X", "NOP": "X", "HOU": "X", "DAL": "X", "SAS": "X", "OKC": "X", "MIN": "X", "DEN": "Y", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "G"},
|
|
"SAC": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "X", "MIL": "X", "MEM": "X", "NOP": "X", "HOU": "X", "DAL": "X", "SAS": "X", "OKC": "X", "MIN": "X", "DEN": "G", "UTA": "G", "PHX": "G", "LAC": "G", "LAL": "G", "GSW": "G", "SAC": "G", "POR": "G"},
|
|
"POR": {"BOS": "X", "TOR": "X", "NYK": "X", "BKN": "X", "PHI": "X", "WAS": "X", "CHA": "X", "ATL": "X", "ORL": "X", "MIA": "X", "DET": "X", "CLE": "X", "IND": "X", "CHI": "X", "MIL": "X", "MEM": "X", "NOP": "X", "HOU": "X", "DAL": "X", "SAS": "X", "OKC": "X", "MIN": "X", "DEN": "Y", "UTA": "G", "PHX": "G", "LAC": "Y", "LAL": "Y", "GSW": "G", "SAC": "G", "POR": "G"}
|
|
}
|
|
|
|
bad_travels = [ (getTeamIdByName[teamByShort[t2]],getTeamIdByName[teamByShort[t1]],b2bmatrix[t1][t2]) for t1 in b2bmatrix.keys() for t2 in b2bmatrix.keys() if b2bmatrix[t1][t2]!="G"]
|
|
|
|
east_teams = [ t for t in realteams if t_lon[t]>= -87]
|
|
center_teams = [ t for t in realteams if -87 > t_lon[t] and t_lon[t]>=-100 ]
|
|
mountain_teams = [ t for t in realteams if -100 > t_lon[t] and t_lon[t]>=-113 ]
|
|
west_teams = [ t for t in realteams if t_lon[t]< -113]
|
|
|
|
# print (len (east_teams))
|
|
# print (len (center_teams))
|
|
# print (len (mountain_teams))
|
|
# for t in mountain_teams:
|
|
# print (" mt " , getTeamById[t])
|
|
# print (len (west_teams))
|
|
|
|
|
|
back2backBlocks += [ (east_teams, mountain_teams+west_teams,1.0), (mountain_teams+west_teams,east_teams,1.0),
|
|
(center_teams,west_teams,1.0) ,(west_teams,center_teams,1.0),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["MEM","NOP","HOU","DAL","SAS","OKC","MIN"]],[getTeamIdByName[teamByShort[ts]] for ts in ["BOS", "TOR", "NYK", "BKN", "PHI", "WAS"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["BOS", "TOR", "NYK", "BKN", "PHI", "WAS"]], [getTeamIdByName[teamByShort[ts]] for ts in ["NOP","HOU","DAL","SAS","OKC"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["DEN", "UTA", "PHX"]], [getTeamIdByName[teamByShort[ts]] for ts in ["CHI","MIL","MEM","NOP","HOU"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["ORL", "MIA"]], [getTeamIdByName[teamByShort[ts]] for ts in ["TOR","MIN"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["NOP", "HOU", "DAL", "SAS"]], [getTeamIdByName[teamByShort[ts]] for ts in ["DET","CLE"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in ["TOR", "CHI", "MIL", "MIN","OKC"]], [getTeamIdByName[teamByShort[ts]] for ts in ["ORL","MIA"]],0.05),
|
|
([getTeamIdByName[teamByShort[ts]] for ts in [ "CHI", "MIL", "MEM","NOP"]], [getTeamIdByName[teamByShort[ts]] for ts in ["UTA","PHX"]],0.05),
|
|
]
|
|
|
|
playingAwayEast = { (t,r) : lpSum([ x[(t1,t,rd )] for rd in getRoundDaysByRound[r] for t1 in east_teams ]) for r in rounds for t in realteams }
|
|
playingAwayWest = { (t,r) : lpSum([ x[(t1,t,rd )] for rd in getRoundDaysByRound[r] for t1 in west_teams+mountain_teams ]) for r in rounds for t in realteams }
|
|
|
|
for t in realteams:
|
|
for r in rounds:
|
|
if r>1:
|
|
model2 += playingAwayEast[(t,r-1)] + playingAwayWest[(t,r)] <=1 + eastWestTrip_NBA[(t,r)]
|
|
model2 += playingAwayWest[(t,r-1)] + playingAwayEast[(t,r)] <=1 + eastWestTrip_NBA[(t,r)]
|
|
|
|
|
|
for t in teams:
|
|
for r in rounds:
|
|
if r>2:
|
|
model2 += awayInRound[(t,r-1)] <= awayInRound[(t,r-2)] + awayInRound[(t,r)] + 3*eastWestTrip_NBA[(t,r)]
|
|
|
|
|
|
for t in west_teams+mountain_teams:
|
|
for r in rounds:
|
|
if r>2:
|
|
model2 += playingAwayEast[(t,r-1)] <= playingAwayEast[(t,r-2)] + playingAwayEast[(t,r)] + 0.3*eastWestTrip_NBA[(t,r)]
|
|
|
|
for t in east_teams:
|
|
for r in rounds:
|
|
if r>2:
|
|
model2 += playingAwayWest[(t,r-1)] <= playingAwayWest[(t,r-2)] + playingAwayWest[(t,r)] + 0.3*eastWestTrip_NBA[(t,r)]
|
|
|
|
|
|
# for t1 in teams:
|
|
# print ("bad travel in ", getTeamById[t1] , bad_travel_in[t1] )
|
|
# print ("bad travel out ", getTeamById[t1] , bad_travel_out[t1] )
|
|
|
|
# distant_teams = { t: [] for t in realteams}
|
|
|
|
# for t in east_teams:
|
|
# print ("EAST " , getTeamById[t], t_lon[t])
|
|
# # distant_teams[t]= mountain_teams+west_teams
|
|
# for t in center_teams:
|
|
# print ("CENTER " , getTeamById[t], t_lon[t])
|
|
# # distant_teams[t]= west_teams
|
|
# for t in mountain_teams:
|
|
# print ("MOUNTAIN " , getTeamById[t], t_lon[t])
|
|
# # distant_teams[t]= east_teams
|
|
# for t in west_teams:
|
|
# print ("WEST " , getTeamById[t], t_lon[t])
|
|
# # distant_teams[t]= center_teams+east_teams
|
|
|
|
# print ("building back to back contraints for " , t)
|
|
badRepeater_Total_NBA = lpSum([badRepeater[(t,r)] for t in teams for r in rounds])
|
|
tooLongTrip_Total_NBA = lpSum([tooLongTrip_NBA[(t,r)] for t in teams for r in rounds])
|
|
eastWestTrip_Total_NBA = lpSum([eastWestTrip_NBA[(t,r)] for t in teams for r in rounds])
|
|
specialObjectives+=10*( badRepeater_Total_NBA)+100*tooLongTrip_Total_NBA + 100*eastWestTrip_Total_NBA
|
|
|
|
|
|
if mathModelName=="UEFA" :
|
|
|
|
isUEL = thisSeason.nicename[:3]=="UEL"
|
|
|
|
for sw in ["UsePosition14", "UseClassicWeekdayPatterns", "Sync1256", "UseClassicSchedules", "UseRedBlueGroups", "MaxAverageEarlyGlobal", "AvoidEarlyDomestic", "AvoidEarlyGlobal", "AvoidEarlyHighDomestic", "AvoidEarlyHighGlobal", "EachOnce", "3breaks", "firstlegs", "NoThreeTuesdaysWednesdays", "OneTuesdayOneWednesday", "everyEncounterOnceEarly"]:
|
|
if sw not in sw_prio.keys():
|
|
sw_prio[sw]=0
|
|
sw_int1[sw]=0
|
|
|
|
show_TV_markets = True
|
|
|
|
model2+=pairingVioTotal==0
|
|
# Sogar hart : Avoid playing early the match with the highest global coefficient of the night (if two matches have the same, one late is enough) à priority B
|
|
|
|
use_classic_schedule= sw_prio['UseClassicSchedules']+sw_prio['UseClassicWeekdayPatterns']>0
|
|
|
|
if thisSeason.nicename[:3]=="UEL" :
|
|
for t in teams:
|
|
# model2 += lpSum([home_time[t,d,getIdByTime["Early"]] + away_time[t,d,getIdByTime["Early"]] for d in days ]) == 3
|
|
print ("3 early games for ", getTeamById[t])
|
|
if use_classic_schedule:
|
|
model2 += lpSum([home_time[t,d,getIdByTime["Early"]] + away_time[t,d,getIdByTime["Early"]] for (r,d) in getRoundDaysByRound[2] ]) == lpSum([home_time[t,d,getIdByTime["Early"]] + away_time[t,d,getIdByTime["Early"]] for (r,d) in getRoundDaysByRound[3] ])
|
|
model2 += lpSum([home_time[t,d,getIdByTime["Early"]] + away_time[t,d,getIdByTime["Early"]] for (r,d) in getRoundDaysByRound[2] ]) == lpSum([home_time[t,d,getIdByTime["Early"]] + away_time[t,d,getIdByTime["Early"]] for (r,d) in getRoundDaysByRound[5] ])
|
|
|
|
|
|
# for pair in pairings:
|
|
# t1 = pair['team1_id']
|
|
# t2 = pair['team2_id']
|
|
# # print ("+++ " ,t_conference[t1] , t_conference[t2] )
|
|
# if t_conference[t1].name[:3] != t_conference[t2].name[:3] :
|
|
# print ("+++ " ,t_conference[t1] , t_conference[t2], " ", getTeamById[t1] , getTeamById[t2])
|
|
|
|
uefa_games = [ (t1,t2) for t1 in teams for t2 in teams if t1<t2 and t_conference[t1]==t_conference[t2] ]
|
|
uefa_interesting_games = [ (t1,t2) for (t1,t2) in uefa_games if quality_of_game(t1,t2)>4 ]
|
|
|
|
# best_glo= {(t1,t2,d) : pulp.LpVariable('best_glo_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t1 in teams for t2 in teams for d in days }
|
|
best_glo= {(t1,t2,d) : pulp.LpVariable('best_glo_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for (t1,t2) in uefa_interesting_games for d in days }
|
|
best_global_early = { d : pulp.LpVariable('best_global_early_'+str(d), lowBound = 0, cat = pulp.LpContinuous) for d in days }
|
|
|
|
NAS15=["ESP","GER","ENG","ITA","FRA"]
|
|
uefa_interesting_domestic_games = {c:[] for c in NAS15}
|
|
uefa_interesting_domestic_teams = {c:set([]) for c in NAS15}
|
|
|
|
|
|
for (t1,t2) in uefa_games:
|
|
if quality_of_game_dom(t1, t2)>=10 and t_country[t1] in NAS15:
|
|
uefa_interesting_domestic_games[t_country[t1]].append((t1,t2))
|
|
uefa_interesting_domestic_teams[t_country[t1]].add(t1)
|
|
if quality_of_game_dom(t2, t1)>=10 and t_country[t2] in NAS15:
|
|
uefa_interesting_domestic_games[t_country[t2]].append((t1,t2))
|
|
uefa_interesting_domestic_teams[t_country[t2]].add(t2)
|
|
|
|
# print ("cool domestic ", uefa_interesting_domestic_games)
|
|
# for c in NAS15:
|
|
# print (c)
|
|
# for (t1,t2) in uefa_interesting_domestic_games[c]:
|
|
# print (getTeamById[t1], getTeamById[t2] , quality_of_game_dom(t1, t2),quality_of_game_dom(t2, t1))
|
|
# for t1 in uefa_interesting_domestic_teams[c]:
|
|
# print (getTeamById[t1])
|
|
# exit(0)
|
|
best_dom= {(c,t1,t2,d) : pulp.LpVariable('best_dom_'+c+'_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for c in NAS15 for (t1,t2) in uefa_interesting_domestic_games[c] for d in days }
|
|
best_dom_early = { (c,d) : pulp.LpVariable('best_dom_early_'+str(d) + '_'+str(c), lowBound = 0, cat = pulp.LpContinuous) for d in days for c in NAS15 }
|
|
|
|
|
|
if thisSeason.nicename[:3]=="UCL" :
|
|
for (t1,t2) in uefa_interesting_games :
|
|
for (r,d) in roundDays:
|
|
model2 += best_glo[(t1,t2,d) ] <= x[(t1,t2,(r,d)) ] + x[(t2,t1,(r,d)) ]
|
|
|
|
for d in days:
|
|
model2+= lpSum( [ best_glo[(t1,t2,d)] for (t1,t2) in uefa_interesting_games]) == 1
|
|
rd =getRoundDaysByDay[d]
|
|
for t in teams:
|
|
model2+= lpSum( [ quality_of_game(t1,t2)*(x[t1,t2,rd]+ x[t2,t1,rd]) for rd in getRoundDaysByDay[d] for (t1,t2) in uefa_interesting_games if t in [t1,t2]]) \
|
|
<= lpSum( [ best_glo[(t1,t2,d)]*quality_of_game(t1,t2) for (t1,t2) in uefa_interesting_games ])
|
|
|
|
# Avoid the match with the highest global coefficient of the night to be played early (if two matches have the same, one late is enough) (preference)")
|
|
for (t1,t2) in uefa_interesting_games :
|
|
rd= getRoundDaysByDay[d][0]
|
|
model2 += best_glo[(t1,t2,d) ] <= x_time[(t1,t2,rd,getIdByTime["Late"])] + x_time[(t2,t1,rd,getIdByTime["Late"])] + best_global_early[d]
|
|
|
|
|
|
# TODO
|
|
# Avoid playing early the match with the highest domestic coefficient in NAs 1-5 if it is 10 or more à priority B
|
|
# nas 5 fran
|
|
|
|
for c in NAS15:
|
|
for (t1,t2) in uefa_interesting_domestic_games[c]:
|
|
for (r,d) in roundDays:
|
|
model2 += best_dom[(c,t1,t2,d) ] <= x[(t1,t2,(r,d)) ] + x[(t2,t1,(r,d)) ]
|
|
|
|
for d in days:
|
|
model2+= lpSum( [ best_dom[(c,t1,t2,d)] for (t1,t2) in uefa_interesting_domestic_games[c]]) <= 1
|
|
rd =getRoundDaysByDay[d]
|
|
for t in uefa_interesting_domestic_teams[c]:
|
|
model2+= lpSum( [ quality_of_game_dom(t1,t2)*(x[t1,t2,rd]+ x[t2,t1,rd]) for rd in getRoundDaysByDay[d] for (t1,t2) in uefa_interesting_domestic_games[c] if t in [t1,t2]]) \
|
|
<= lpSum( [ best_dom[(c,t1,t2,d)]*quality_of_game_dom(t1,t2) for (t1,t2) in uefa_interesting_domestic_games[c] ])
|
|
|
|
# Avoid the match with the highest global coefficient of the night to be played early (if two matches have the same, one late is enough) (preference)")
|
|
for (t1,t2) in uefa_interesting_domestic_games[c]:
|
|
rd= getRoundDaysByDay[d][0]
|
|
model2 += best_dom[(c,t1,t2,d)] <= x_time[(t1,t2,rd,getIdByTime["Late"])] + x_time[(t2,t1,rd,getIdByTime["Late"])] + best_dom_early[(c,d)]
|
|
|
|
|
|
# forall (r in ROUNDS, c in NA14COUNTRIES | 1=1) do
|
|
# sum(t1, t2 in TEAMS | COUNTRY(t1)=c ) best_dom(t1,t2,r) =1
|
|
# forall (t1 in TEAMS | COUNTRY(t1)=c ) do
|
|
# sum (t2 in TEAMS| GROUP(t1)=GROUP(t2) and t1<>t2 and quality_of_game_dom(t1,t2)>4 ) quality_of_game_dom(t1,t2)*(x(t1,t2,r)+x(t2,t1,r)) <= sum(t3,t4 in TEAMS| COUNTRY(t3)=c and GROUP(t3)=GROUP(t4) and t3<>t4) quality_of_game_dom(t3,t4)*best_dom(t3,t4,r)
|
|
# end-do
|
|
# end-do
|
|
|
|
|
|
# writeln ("Avoid the match with the highest domestic coefficient to be played early in NAs 1-5 if it is 10 or more (preference)")
|
|
# forall (c in NA14COUNTRIES, r in ROUNDS ) do
|
|
# ! Avoid the match with the highest domestic coefficient in NAs 1-5 if it is 10 or more 50
|
|
# ! - put the best domestic coeff match late, if value >10
|
|
|
|
# forall (t1,t2 in TEAMS | exists(x(t1,t2,r)) and COUNTRY(t1)=c )
|
|
# if ( quality_of_game_dom(t1,t2) >=10 ) then
|
|
# best_dom(t1,t2,r) <= y(t1,t2,r,1)+ y(t2,t1,r,1) + best_dom_early(r,c)
|
|
# end-if
|
|
|
|
|
|
specialObjectives= (0.01*sum([quality_of_game(t1,t2) * x_time[(t1,t2,rd,getIdByTime["Early"])] for (t1,t2,rd) in x.keys()])
|
|
# Avoid early matches with a global coefficient of 16 and more (60)
|
|
+0.6*0.2*sw_prio["AvoidEarlyGlobal"]*sum([quality_of_game(t1,t2) * x_time[(t1,t2,rd,getIdByTime["Early"])] for (t1,t2,rd) in x.keys() if quality_of_game(t1,t2)>=sw_int1["AvoidEarlyGlobal"]])
|
|
# Maximise the average global coefficient of early matches (should stay under 16) à priority C
|
|
-0.1*sw_prio["MaxAverageEarlyGlobal"]*sum([quality_of_game(t1,t2) * x_time[(t1,t2,rd,getIdByTime["Early"])] for (t1,t2,rd) in x.keys() if quality_of_game(t1,t2)<sw_int1["MaxAverageEarlyGlobal"]])
|
|
# Avoid early matches with a domestic coefficient of 25 and more (60)
|
|
+0.6*0.2*sw_prio["AvoidEarlyDomestic"]*sum([quality_of_game(t1,t2) * x_time[(t1,t2,rd,getIdByTime["Early"])] for (t1,t2,rd) in x.keys() if quality_of_game_dom(t1,t2)>=sw_int1["AvoidEarlyDomestic"] or quality_of_game_dom(t2,t1)>=sw_int1["AvoidEarlyDomestic"] ])
|
|
-0.1*sum([quality_of_game(t1,t2) * best_glo[(t1,t2,d)] for (t1,t2) in uefa_interesting_games for d in days ])
|
|
+0.5*0.04*sw_prio["AvoidEarlyHighDomestic"]*sum([best_global_early[d] for d in days ])
|
|
+5*0.04*sw_prio["AvoidEarlyHighGlobal"]*sum([best_dom_early[(c,d)] for c in NAS15 for d in days ])
|
|
)
|
|
|
|
model2+= standardObjectives +specialObjectives
|
|
|
|
|
|
# todo : MORE PATTERNS
|
|
positions = range (1,9)
|
|
# pos= {(t,p) : pulp.LpVariable('pos_'+str(t)+'_'+str(p), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t in teams for p in positions }
|
|
pos= {(t,p) : pulp.LpVariable('pos_'+str(t)+'_'+str(p), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t in teams for p in positions }
|
|
|
|
for c in displayGroups.keys():
|
|
for p in positions:
|
|
model2+= lpSum( [ pos[t,p] for t in displayGroups[c]]) <= 1
|
|
model2+= lpSum( [ pos[t,1]-pos[t,2] for t in displayGroups[c]]) == 0
|
|
model2+= lpSum( [ pos[t,3]-pos[t,4] for t in displayGroups[c]]) == 0
|
|
model2+= lpSum( [ pos[t,5]-pos[t,6] for t in displayGroups[c]]) == 0
|
|
model2+= lpSum( [ pos[t,7]-pos[t,8] for t in displayGroups[c]]) == 0
|
|
|
|
|
|
for (t1,t2) in uefa_games:
|
|
# Each team has to play each opponent on a Tuesday and on a Wednesday
|
|
print (getTeamById[t1], getTeamById[t2])
|
|
if sw_prio['OneTuesdayOneWednesday']>0 and len([d for d in days if getWeekDay[d]=="Tue"])>0:
|
|
model2+= lpSum([(x[t1,t2,(r,d)]+x[t2,t1,(r,d)]) for (r,d) in roundDays if getWeekDay[d]=="Tue"]) == 1
|
|
|
|
if use_classic_schedule:
|
|
# model2 += pos[t1,4] + pos[t2,1] - 1 <= lpSum([x[t1,t2,rd] for rd in getRoundDaysByRound[1]])
|
|
# model2 += pos[t2,4] + pos[t1,1] - 1 <= lpSum([x[t2,t1,rd] for rd in getRoundDaysByRound[1]])
|
|
|
|
# model2 += pos[t1,1] + pos[t2,2] - 1 <= lpSum([x[t1,t2,rd] for rd in getRoundDaysByRound[2]])
|
|
# model2 += pos[t2,1] + pos[t1,2] - 1 <= lpSum([x[t2,t1,rd] for rd in getRoundDaysByRound[2]])
|
|
|
|
# model2 += pos[t1,3] + pos[t2,1] - 1 <= lpSum([x[t1,t2,rd] for rd in getRoundDaysByRound[3]])
|
|
# model2 += pos[t2,3] + pos[t1,1] - 1 <= lpSum([x[t2,t1,rd] for rd in getRoundDaysByRound[3]])
|
|
|
|
model2 += lpSum([ pos[t,p] for t in [t1,t2] for p in [1,4] ])-1 <= lpSum([(x[t1,t2,rd]+x[t2,t1,rd]) for rd in getRoundDaysByRound[1]])
|
|
model2 += lpSum([ pos[t,p] for t in [t1,t2] for p in [1,2] ])-1 <= lpSum([(x[t1,t2,rd]+x[t2,t1,rd]) for rd in getRoundDaysByRound[2]])
|
|
# model2 += lpSum([ pos[t,p] for t in [t1,t2] for p in [1,3] ])-1 <= lpSum([(x[t1,t2,rd]+x[t2,t1,rd]) for rd in getRoundDaysByRound[3]])
|
|
|
|
model2 += lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[1]]) == lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[5]])
|
|
model2 += lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[2]]) == lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[6]])
|
|
# model2 += lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[3]]) == lpSum([x[t1,t2,rd]+x[t2,t1,rd] for rd in getRoundDaysByRound[4]])
|
|
|
|
# every encounter once early once late
|
|
if sw_prio['everyEncounterOnceEarly']>0 :
|
|
model2+= lpSum([( x_time[(t1,t2,rd,getIdByTime["Early"])] + x_time[(t2,t1,rd,getIdByTime["Early"])] ) for rd in roundDays ]) == 1
|
|
|
|
|
|
# implement classic Tue/Wed patterns
|
|
# 1 2 3 4 5 6 7 8 9 10 11 12
|
|
# x x x x x x
|
|
if sw_prio['UseClassicWeekdayPatterns']>0:
|
|
# print ("using red/blue")
|
|
uefa_group_is_blue = {c : pulp.LpVariable('uefa_groupcolor_'+str(c), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for c in displayGroups.keys() }
|
|
bluetuesdays = [ d for d in days if getRoundByDay[d] in [1,4,6] and getWeekDay[d]=="Tue"]
|
|
bluewednesdays = [ d for d in days if getRoundByDay[d] in [2,3,5] and getWeekDay[d]=="Wed" ]
|
|
model2+= lpSum([uefa_group_is_blue[c] for c in displayGroups.keys()]) == 0.5*len(displayGroups.keys())
|
|
for t in teams:
|
|
for d in bluetuesdays:
|
|
model2+= home[(t,d)]+away[(t,d)] == uefa_group_is_blue[t_conference[t].name]
|
|
for d in bluewednesdays:
|
|
model2+= home[(t,d)]+away[(t,d)] == uefa_group_is_blue[t_conference[t].name]
|
|
|
|
if sw_prio['Sync1256']>0:
|
|
for (t1,t2) in uefa_games:
|
|
for d in days:
|
|
# groups play same days in rounds 1,2,5,6
|
|
if getRoundByDay[d] in [1,2,5,6] + [3,4]:
|
|
model2+= home[(t1,d)]+away[(t1,d)] == home[(t2,d)]+away[(t2,d)]
|
|
|
|
for t in teams:
|
|
model2 += lpSum( [ pos[t,p] for p in positions ]) ==1
|
|
model2 += homeInRound[t,1]== pos[t,2] +pos[t,4] +pos[t,5] +pos[t,7]
|
|
model2 += homeInRound[t,2]== pos[t,1] +pos[t,3] + pos[t,6] +pos[t,8]
|
|
model2 += homeInRound[t,3]== pos[t,2] +pos[t,3] + pos[t,6] +pos[t,7]
|
|
model2 += homeInRound[t,4]== pos[t,1] +pos[t,4] +pos[t,5] +pos[t,8]
|
|
model2 += homeInRound[t,5]== pos[t,1] +pos[t,3] +pos[t,5] +pos[t,7]
|
|
model2 += homeInRound[t,6]== pos[t,2] +pos[t,4] + pos[t,6] +pos[t,8]
|
|
if use_classic_schedule or sw_prio['UsePosition14']:
|
|
model2 += pos[t,5]==0
|
|
model2 += pos[t,6]==0
|
|
model2 += pos[t,7]==0
|
|
model2 += pos[t,8]==0
|
|
print ("forbidding " ,t, 5,6,7,8)
|
|
else:
|
|
model2 += pos[t,1]==0
|
|
model2 += pos[t,2]==0
|
|
model2 += pos[t,3]==0
|
|
model2 += pos[t,4]==0
|
|
|
|
if sw_prio['NoThreeTuesdaysWednesdays']>0 :
|
|
for t in teams:
|
|
model2+= lpSum([ home[t,d]+away[t,d] for (r,d) in roundDays if getWeekDay[d]=="Tue" and r<=2]) == 1
|
|
model2+= lpSum([ home[t,d]+away[t,d] for (r,d) in roundDays if getWeekDay[d]=="Tue" and r>=5]) == 1
|
|
|
|
|
|
print ("EXTRA UEFA UCL/UEL run")
|
|
writeProgress("Running special model ", thisScenario.id,10)
|
|
|
|
print (confTeams.keys())
|
|
print (confName)
|
|
# for cname in ["Group A" ,"Group B" ,"UCL" , "UEL Group D" ,"UEL Group A" ,"UEL Group B" , "UEL Group C", "UEL Group E", "UEL Group F", "UEL" , "UECL" ]:
|
|
for cname in ["Group A" ,"Group B" ,"UCL" , "UEL Group D" ,"UEL Group A" ,"UEL Group B" , "UEL" , "UECL" ]:
|
|
# for cname in ["UCL", "UEL", "UECL"]:
|
|
print ("TRYING ", cname)
|
|
for c in confTeams.keys():
|
|
# print (confName[c],cname,confName[c]==cname)
|
|
if confName[c]==cname :
|
|
print ()
|
|
print ()
|
|
print (confName[c])
|
|
print ("confTeams" , confTeams[c])
|
|
for p in positions:
|
|
for t in confTeams[c]:
|
|
pos[t,p].cat = pulp.LpInteger
|
|
|
|
if runMode!='Improve':
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=0.2, TimeLimit=120, msg=1))
|
|
else:
|
|
model2.solve(XPRESS(msg=1,maxSeconds=60, keepFiles=True))
|
|
|
|
# posTeam = { p : t for p in positions for t in confTeams[c] if pos[(t,p)].value()>0.9 }
|
|
# print ("posTeam",posTeam)
|
|
for p in positions:
|
|
for t in confTeams[c]:
|
|
if pos[(t,p)].value()>0.9:
|
|
model2 += pos[(t,p)] == pos[(t,p)].value()
|
|
print(p,t)
|
|
|
|
for (t1,t2) in uefa_games:
|
|
if t1 in confTeams[c]:
|
|
for rd in roundDays:
|
|
if isUEL:
|
|
makeIntVar(x_time[t1,t2,rd,getIdByTime["Early"]])
|
|
else:
|
|
makeIntVar(x[t1,t2,rd])
|
|
|
|
|
|
# if solver == "CBC":
|
|
# model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
# elif solver == "Gurobi":
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=120, msg=1))
|
|
# else:
|
|
# model2.solve(XPRESS(msg=1,maxSeconds=60, keepFiles=True))
|
|
|
|
# for (t1,t2) in uefa_games:
|
|
# if t1 in confTeams[c]:
|
|
# for rd in roundDays:
|
|
# if getVal(x[t1,t2,rd]):
|
|
# setLB(x[t1,t2,rd],1)
|
|
|
|
# model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
# model2+= lpSum( [ - pos[t,p] for p in positions ])
|
|
|
|
# if solver == "CBC":
|
|
# model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
# elif solver == "Gurobi":
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=120,msg=1))
|
|
# else:
|
|
# model2.solve(XPRESS(msg=1,maxSeconds = 80, keepFiles=True))
|
|
|
|
# for (t,p) in pos.keys():
|
|
# if pos[(t,p)].value()>0.9:
|
|
# print ("position ", p , " for " , t)
|
|
# model2 += pos[(t,p)] == pos[(t,p)].value()
|
|
|
|
# best_glo= {(t1,t2,d) : pulp.LpVariable('best_glo_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpContinuous)
|
|
if False:
|
|
for d in days:
|
|
print (getNiceDay[d] )
|
|
for (t1,t2) in uefa_interesting_games:
|
|
if best_glo[(t1,t2,d)].value()>0.01:
|
|
print (" Best GLO ",quality_of_game(t1,t2), getTeamById[t1] , getTeamById[t2] , 0.01*int(100*best_glo[(t1,t2,d)].value()) )
|
|
print ()
|
|
for c in NAS15:
|
|
print ( "checking " , c, uefa_interesting_domestic_games[c] )
|
|
for (t1,t2) in uefa_interesting_domestic_games[c]:
|
|
print ( " -- " , getTeamById[t1] , getTeamById[t2] )
|
|
print ( " --- " , (c,t1,t2,d) in best_dom.keys() )
|
|
print ( " ---- " , best_dom[(c,t1,t2,d)].value() , best_dom[(c,t1,t2,d)].value() ==None )
|
|
if not (c,t1,t2,d) in best_dom.keys() :
|
|
print (c,t1,t2,d, " not in " , best_dom)
|
|
if best_dom[(c,t1,t2,d)].value() and best_dom[(c,t1,t2,d)].value()>0.01:
|
|
print (" Best DOM ",c ,getTeamById[t1] , getTeamById[t2] , 0.01*int(100*best_dom[(c,t1,t2,d)].value()))
|
|
|
|
|
|
if mathModelName=="EuroLeague Basketball" :
|
|
show_TV_markets = True
|
|
|
|
day2pairs =[ (d1,d2) for d1 in days for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] ==datetime.timedelta(days=2) and getRoundByDay[d1] <37]
|
|
# trip_ebl= {(t,d) : pulp.LpVariable('trip_'+str(t)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t in teams for (d,d2) in day2pairs}
|
|
|
|
print ("day2pairs", day2pairs)
|
|
|
|
doubleWeekendDays = { d1 : [d1,d2,d3,d4] for (d1,d2) in day2pairs for (d3,d4) in day2pairs if getDateTimeDay[d3]-getDateTimeDay[d1] ==datetime.timedelta(days=1) }
|
|
print ("doubleWeekendDays", doubleWeekendDays)
|
|
|
|
criticalDayPairs = [ (d1,d2) ]
|
|
|
|
getDW = { getDayById[dw]["round"] : dw for dw in doubleWeekendDays.keys() }
|
|
|
|
elb_rounds = getDW.keys()
|
|
elb_rounds1 = [ r for r in elb_rounds if r <= nRounds1]
|
|
elb_rounds2 = [ r for r in elb_rounds if r > nRounds1]
|
|
|
|
criticalAvailabilities = {r: [] for r in elb_rounds}
|
|
for d1 in doubleWeekendDays.keys():
|
|
dd = doubleWeekendDays[d1]
|
|
for day in [dd[0],dd[3]]:
|
|
criticalAvailabilities[ getRoundByDay[day] ] =[t for t in teams if available_days[t,day]==0]
|
|
|
|
canTravel={t: elb_rounds for t in teams }
|
|
|
|
|
|
# closeTeams_EBL_raw={'ALBA Berlin': ['FC Bayern Munich', 'Crvena Zvezda mts Belgrade', 'Zalgiris Kaunas', 'LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'Zenit St. Petersburg', 'CSKA Moscow', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'FC Barcelona', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'AS Monaco'], 'Anadolu Efes Istanbul': ['Maccabi FOX Tel Aviv', 'Fenerbahce Beko Istanbul', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'CSKA Moscow', 'Crvena Zvezda mts Belgrade', 'UNICS Kazan', 'Zalgiris Kaunas', 'ALBA Berlin', 'FC Bayern Munich', 'AX Armani Exchange Milan'], 'AS Monaco': ['LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'FC Barcelona', 'Real Madrid', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'TD Systems Baskonia Vitoria-Gasteiz'], 'AX Armani Exchange Milan': ['LDLC ASVEL Villeurbanne', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'FC Barcelona', 'Real Madrid', 'TD Systems Baskonia Vitoria-Gasteiz', 'AS Monaco', 'Zalgiris Kaunas'], 'Crvena Zvezda mts Belgrade': ['ALBA Berlin', 'FC Bayern Munich', 'AX Armani Exchange Milan', 'LDLC ASVEL Villeurbanne', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'Zalgiris Kaunas', 'Maccabi FOX Tel Aviv', 'FC Barcelona', 'CSKA Moscow', 'AS Monaco'], 'CSKA Moscow': ['Zenit St. Petersburg', 'Zalgiris Kaunas', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'UNICS Kazan', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul'], 'FC Barcelona': ['Real Madrid', 'TD Systems Baskonia Vitoria-Gasteiz', 'AS Monaco', 'LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus'], 'FC Bayern Munich': ['ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Zalgiris Kaunas', 'LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'AS Monaco', 'Zenit St. Petersburg', 'CSKA Moscow', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'FC Barcelona', 'Real Madrid', 'TD Systems Baskonia Vitoria-Gasteiz', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul'], 'Fenerbahce Beko Istanbul': ['Maccabi FOX Tel Aviv', 'Anadolu Efes Istanbul', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'CSKA Moscow', 'UNICS Kazan', 'Crvena Zvezda mts Belgrade', 'Zalgiris Kaunas', 'ALBA Berlin', 'FC Bayern Munich', 'AX Armani Exchange Milan'], 'LDLC ASVEL Villeurbanne': ['AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'FC Barcelona', 'Real Madrid', 'TD Systems Baskonia Vitoria-Gasteiz', 'AS Monaco', 'Zalgiris Kaunas'], 'Maccabi FOX Tel Aviv': ['Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'Crvena Zvezda mts Belgrade'], 'Olympiacos Piraeus': ['Panathinaikos OPAP Athens', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Maccabi FOX Tel Aviv', 'Crvena Zvezda mts Belgrade', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'FC Barcelona', 'LDLC ASVEL Villeurbanne', 'AS Monaco'], 'Panathinaikos OPAP Athens': ['Olympiacos Piraeus', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Maccabi FOX Tel Aviv', 'Crvena Zvezda mts Belgrade', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'FC Barcelona', 'LDLC ASVEL Villeurbanne', 'AS Monaco'], 'Real Madrid': ['TD Systems Baskonia Vitoria-Gasteiz', 'FC Barcelona', 'LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus', 'AS Monaco'], 'TD Systems Baskonia Vitoria-Gasteiz': ['Real Madrid', 'FC Barcelona', 'AS Monaco', 'LDLC ASVEL Villeurbanne', 'AX Armani Exchange Milan', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Panathinaikos OPAP Athens', 'Olympiacos Piraeus'], 'UNICS Kazan': ['CSKA Moscow', 'Zenit St. Petersburg', 'Zalgiris Kaunas', 'Crvena Zvezda mts Belgrade', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul'], 'Zalgiris Kaunas': ['Zenit St. Petersburg', 'CSKA Moscow', 'UNICS Kazan', 'ALBA Berlin', 'FC Bayern Munich', 'AX Armani Exchange Milan', 'LDLC ASVEL Villeurbanne', 'Crvena Zvezda mts Belgrade', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul'], 'Zenit St. Petersburg': ['CSKA Moscow', 'UNICS Kazan', 'Zalgiris Kaunas', 'ALBA Berlin', 'FC Bayern Munich']}
|
|
closeTeams_EBL_raw= {
|
|
'ALBA Berlin': ['FC Bayern Munich','Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade',
|
|
'Zalgiris Kaunas', 'LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan',
|
|
'AS Monaco','Panathinaikos OPAP Athens' , 'Olympiacos Piraeus','Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul',],
|
|
'Anadolu Efes Istanbul': ['Maccabi Playtika Tel Aviv', 'Fenerbahce Beko Istanbul', 'Olympiacos Piraeus',
|
|
'Panathinaikos OPAP Athens', 'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade',
|
|
'Zalgiris Kaunas', 'ALBA Berlin','FC Bayern Munich', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan'],
|
|
'AS Monaco': ['LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna','AX Armani Exchange Milan', 'FC Bayern Munich', 'FC Barcelona',
|
|
'Real Madrid', 'ALBA Berlin', 'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade','Panathinaikos OPAP Athens' , 'Olympiacos Piraeus', 'Baskonia Vitoria-Gasteiz', 'Valencia Basket', ],
|
|
'AX Armani Exchange Milan': ['Virtus Segafredo Bologna','LDLC ASVEL Villeurbanne', 'FC Bayern Munich', 'ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade',
|
|
'Zalgiris Kaunas','Panathinaikos OPAP Athens' , 'Olympiacos Piraeus', 'FC Barcelona', 'Real Madrid', 'Baskonia Vitoria-Gasteiz', 'Valencia Basket','AS Monaco'],
|
|
'Crvena Zvezda mts Belgrade': [ 'Partizan Nis Belgrade', 'ALBA Berlin', 'FC Bayern Munich', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan',
|
|
'LDLC ASVEL Villeurbanne','Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Olympiacos Piraeus', 'Panathinaikos OPAP Athens','Zalgiris Kaunas','Maccabi Playtika Tel Aviv' , 'AS Monaco'],
|
|
'FC Barcelona': ['Real Madrid', 'Baskonia Vitoria-Gasteiz', 'Valencia Basket', 'AS Monaco', 'AX Armani Exchange Milan', 'LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna',
|
|
'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade', "FC Bayern Munich"],
|
|
'FC Bayern Munich': ['ALBA Berlin', 'Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade','Zalgiris Kaunas',
|
|
'AS Monaco', 'AX Armani Exchange Milan', 'LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna', 'Panathinaikos OPAP Athens' , 'Olympiacos Piraeus',
|
|
'FC Barcelona', 'Real Madrid', 'Baskonia Vitoria-Gasteiz', 'Valencia Basket','Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul' ],
|
|
'Fenerbahce Beko Istanbul': ['Maccabi Playtika Tel Aviv', 'Anadolu Efes Istanbul', 'Olympiacos Piraeus',
|
|
'Panathinaikos OPAP Athens', 'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade',
|
|
'Zalgiris Kaunas', 'ALBA Berlin','FC Bayern Munich', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan'],
|
|
'LDLC ASVEL Villeurbanne': [ 'AS Monaco', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan','FC Bayern Munich','ALBA Berlin',
|
|
'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade','Panathinaikos OPAP Athens' , 'Olympiacos Piraeus',
|
|
'FC Barcelona', 'Real Madrid', 'Valencia Basket', 'Baskonia Vitoria-Gasteiz', ],
|
|
'Maccabi Playtika Tel Aviv': ['Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Partizan Nis Belgrade', 'Crvena Zvezda mts Belgrade','Panathinaikos OPAP Athens' , 'Olympiacos Piraeus', ],
|
|
'Olympiacos Piraeus': [ 'Panathinaikos OPAP Athens', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Maccabi Playtika Tel Aviv',
|
|
'Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade','Virtus Segafredo Bologna', 'AX Armani Exchange Milan','FC Bayern Munich',
|
|
'ALBA Berlin','LDLC ASVEL Villeurbanne','AS Monaco'],
|
|
'Panathinaikos OPAP Athens': [ 'Olympiacos Piraeus', 'Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Maccabi Playtika Tel Aviv',
|
|
'Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade','Virtus Segafredo Bologna', 'AX Armani Exchange Milan','FC Bayern Munich',
|
|
'ALBA Berlin','LDLC ASVEL Villeurbanne','AS Monaco'],
|
|
'Partizan Nis Belgrade' : [ 'Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade', 'ALBA Berlin', 'FC Bayern Munich', 'Virtus Segafredo Bologna', 'AX Armani Exchange Milan',
|
|
'LDLC ASVEL Villeurbanne','Anadolu Efes Istanbul', 'Fenerbahce Beko Istanbul', 'Olympiacos Piraeus', 'Panathinaikos OPAP Athens','Zalgiris Kaunas','Maccabi Playtika Tel Aviv' , 'AS Monaco'],
|
|
'Real Madrid': ['Baskonia Vitoria-Gasteiz', 'FC Barcelona','Valencia Basket', 'LDLC ASVEL Villeurbanne',
|
|
'Virtus Segafredo Bologna', 'AX Armani Exchange Milan','FC Bayern Munich','Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade','AS Monaco' ],
|
|
'Baskonia Vitoria-Gasteiz': [ 'Real Madrid', 'FC Barcelona', 'Valencia Basket','LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna',
|
|
'AX Armani Exchange Milan', 'AS Monaco','FC Bayern Munich' ],
|
|
'Valencia Basket': [ 'Real Madrid', 'FC Barcelona', 'Baskonia Vitoria-Gasteiz','LDLC ASVEL Villeurbanne', 'Virtus Segafredo Bologna',
|
|
'AX Armani Exchange Milan', 'AS Monaco','FC Bayern Munich' ],
|
|
'Virtus Segafredo Bologna': [ 'Real Madrid', 'FC Barcelona','Valencia Basket' , 'Baskonia Vitoria-Gasteiz','LDLC ASVEL Villeurbanne',
|
|
'AX Armani Exchange Milan', 'AS Monaco','FC Bayern Munich' , 'ALBA Berlin','Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade', 'Olympiacos Piraeus', 'Panathinaikos OPAP Athens'],
|
|
'Zalgiris Kaunas': ['ALBA Berlin','FC Bayern Munich','Virtus Segafredo Bologna', 'AX Armani Exchange Milan','Crvena Zvezda mts Belgrade', 'Partizan Nis Belgrade','Anadolu Efes Istanbul',
|
|
'Fenerbahce Beko Istanbul', 'LDLC ASVEL Villeurbanne','AS Monaco']
|
|
}
|
|
|
|
closeTeams_EBL= { getTeamIdByName[tn] : [ getTeamIdByName[tn2] for tn2 in closeTeams_EBL_raw[tn] ] for tn in closeTeams_EBL_raw.keys() }
|
|
|
|
singleTrips_EBL = [ (t1,t2,r) for t2 in teams for t1 in closeTeams_EBL[t2] for r in elb_rounds ]
|
|
|
|
print(elb_rounds)
|
|
|
|
# for t2 in teams:
|
|
# for t1 in closeTeams_EBL[t2]:
|
|
# # if not t2 in closeTeams_EBL[t1]:
|
|
# # print (getTeamById[t2] ," not in list of ", getTeamById[t1])
|
|
# for r in canHostSingle[t1]:
|
|
# print (" single trip in round " ,r , " : ", t1 , t2 , "possible" )
|
|
|
|
print (len (singleTrips_EBL) , " single trips")
|
|
|
|
|
|
conferences_ebl = [c for c in Conference.objects.filter(scenario=s2,regional=False).exclude(name='REOPT')]
|
|
neighbors_ebl = [c for c in Conference.objects.filter(scenario=s2,regional=True).exclude(name='REOPT') ]
|
|
|
|
print ("conferences_ebl", conferences_ebl)
|
|
print ("neighbors_ebl", neighbors_ebl)
|
|
|
|
getConference={}
|
|
getNeighborId={}
|
|
for c in conferences_ebl:
|
|
if len(c.teams.all())>3:
|
|
for t in c.teams.filter(active=True):
|
|
getConference[t.id]=c.id
|
|
else:
|
|
for (d1,d2) in day2pairs:
|
|
print ("forbid games for " , c.name, " in days" , d1,d2)
|
|
# model2 += lpSum( [x[t1.id, t2.id, rd] for t1 in c.teams.all() for t2 in c.teams.all() for rd in getRoundDaysByDay[d1]+getRoundDaysByDay[d2] if t1.id!=t2.id ]) == 0
|
|
|
|
|
|
|
|
getTeamsOfNeighbor={}
|
|
getNameOfNeighbor={}
|
|
getConfId={}
|
|
for c in neighbors_ebl:
|
|
getTeamsOfNeighbor[c.id]=[]
|
|
print (c.id, c.name)
|
|
getConfId[c.name]=c.id
|
|
getNameOfNeighbor[c.id]=c.name
|
|
for t in c.teams.filter(active=True):
|
|
getNeighborId[t.id]=c.id
|
|
getTeamsOfNeighbor[c.id].append(t.id)
|
|
print ( " - " , t.id , "\t",canTravel[t.id], "\t", " " , t.name)
|
|
# otherConference= { t: [ t2 for t2 in teams if getConference[t]!=getConference[t2] ] for t in teams }
|
|
# otherNeighbor= { t: [ t2 for t2 in teams if getNeighborId[t]!=getNeighborId[t2] ] for t in teams if t in getNeighborId.keys()}
|
|
|
|
# print ("otherConference = ", otherConference)
|
|
# print ("otherNeighbor = ", otherNeighbor)
|
|
|
|
|
|
getConfOfNeighbor={}
|
|
getNeighborsInConf={ c : set([]) for c in set(getConference.values()) }
|
|
for t in teams :
|
|
# print (getTeamById[t])
|
|
# print ("-",getNeighborId[t])
|
|
# print ("-",getConference[t])
|
|
|
|
|
|
getConfOfNeighbor[getNeighborId[t]]=getConference[t]
|
|
getNeighborsInConf[getConference[t]].add(getNeighborId[t])
|
|
print (getConference[t],getNeighborId[t], getTeamById[t] )
|
|
|
|
# tripCands=
|
|
|
|
print ("getConfOfNeighbor = ", getConfOfNeighbor)
|
|
print ("getNeighborsInConf = ", getNeighborsInConf)
|
|
|
|
possTrips = {}
|
|
|
|
for g1 in neighbors_ebl:
|
|
for g2 in neighbors_ebl:
|
|
if getConfOfNeighbor[g1.id]!=getConfOfNeighbor[g2.id] :
|
|
for t1 in getTeamsOfNeighbor[g1.id]:
|
|
for t2 in getTeamsOfNeighbor[g2.id]:
|
|
for r in elb_rounds:
|
|
if (t2,r,g1.id) not in possTrips.keys():
|
|
possTrips[t2,r,g1.id]=[]
|
|
possTrips[t2,r,g1.id].append(t1)
|
|
|
|
|
|
remtrg= [ trg for trg in possTrips.keys() if len(possTrips[trg])==1]
|
|
|
|
for trg in remtrg :
|
|
del possTrips[trg]
|
|
|
|
for trg in possTrips.keys():
|
|
print ("++" , trg, possTrips[trg])
|
|
|
|
trips_ebl = [ (t1,t2,r) for (t2,r,g) in possTrips.keys() for t1 in possTrips[(t2,r,g)]]
|
|
|
|
games_ebl= set([(t1,t2) for (t1,t2,r) in trips_ebl + singleTrips_EBL ])
|
|
|
|
far_teams = [(t1,t2) for (t1,t2) in games_ebl if t1 not in closeTeams_EBL[t2]]
|
|
far_teams = {t : [ t1 for (t1,t2) in far_teams if t2==t] for t in teams}
|
|
|
|
# print (far_games)
|
|
|
|
# for t in teams:
|
|
# print (getTeamById[t], " :")
|
|
# for t2 in far_games[t]:
|
|
# print (" - " , getTeamById[t2])
|
|
|
|
|
|
fixed_travels= []
|
|
# fixed_travels= [(283, 15, 'A'), (296, 6, 'A'), (289, 24, 'A'), (293, 31, 'A'), (299, 20, 'A'), (287, 3, 'A'), (288, 10, 'A'), (297, 24, 'A'), (281, 24, 'B'), (283, 6, 'B'), (289, 15, 'B'), (293, 3, 'B'), (299, 6, 'B'), (297, 20, 'B'), (281, 6, 'C'), (296, 31, 'C'), (287, 10, 'C'), (288, 24, 'C'), (286, 20, 'D'), (291, 31, 'D'), (295, 24, 'D'), (282, 20, 'D'), (290, 3, 'D'), (298, 10, 'D'), (294, 15, 'D'), (300, 20, 'D'), (286, 6, 'E'), (291, 3, 'E'), (295, 10, 'E'), (282, 24, 'E'), (298, 31, 'E'), (284, 20, 'E'), (294, 3, 'E'), (300, 10, 'E'), (290, 15, 'F'), (284, 3, 'F')]
|
|
# fixed_travels= [ (getTeamById[t2],r,g) for (t2,r,g) in fixed_travels]
|
|
# fixed_travels= [('Zenit St. Petersburg', 24, 'A'), ('CSKA Moscow', 10, 'A'), ('Fenerbahce Beko Istanbul', 31, 'A'), ('Anadolu Efes Istanbul', 20, 'A'), ('Panathinaikos OPAP Athens', 3, 'A'), ('Olympiacos Piraeus', 24, 'A'), ('Crvena Zvezda mts Belgrade', 10, 'A'), ('UNICS Kazan', 20, 'B'), ('Zenit St. Petersburg', 15, 'B'), ('CSKA Moscow', 6, 'B'), ('Maccabi FOX Tel Aviv', 3, 'B'), ('Anadolu Efes Istanbul', 3, 'B'), ('Olympiacos Piraeus', 31, 'B'), ('Crvena Zvezda mts Belgrade', 6, 'B'), ('UNICS Kazan', 24, 'C'), ('Maccabi FOX Tel Aviv', 24, 'C'), ('Fenerbahce Beko Istanbul', 10, 'C'), ('Panathinaikos OPAP Athens', 10, 'C'), ('Real Madrid', 6, 'D'), ('TD Systems Baskonia Vitoria-Gasteiz', 6, 'D'), ('LDLC ASVEL Villeurbanne', 20, 'D'), ('AX Armani Exchange Milan', 10, 'D'), ('FC Bayern Munich', 3, 'D'), ('ALBA Berlin', 10, 'D'), ('Real Madrid', 31, 'E'), ('TD Systems Baskonia Vitoria-Gasteiz', 15, 'E'), ('FC Barcelona', 6, 'E'), ('AS Monaco', 10, 'E'), ('LDLC ASVEL Villeurbanne', 24, 'E'), ('AX Armani Exchange Milan', 31, 'E'), ('Zalgiris Kaunas', 6, 'E'), ('ALBA Berlin', 20, 'E'), ('FC Barcelona', 15, 'F'), ('AS Monaco', 24, 'F'), ('Zalgiris Kaunas', 3, 'F'), ('FC Bayern Munich', 15, 'F')]
|
|
|
|
print (len (games_ebl))
|
|
|
|
xxx_travel_rounds = sorted( list(elb_rounds) + [ r+1 for r in elb_rounds ])
|
|
|
|
xxx_rounds = xxx_travel_rounds
|
|
# xxx_rounds = rounds
|
|
# xxx_rounds = sorted( list(elb_rounds) + [ r+1 for r in elb_rounds ])
|
|
|
|
travel_to_cluster= {(t2,r,g) : pulp.LpVariable('travel_to_cluster_'+str(t2)+'_'+str(r)+'_'+str(g), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for (t2,r,g) in possTrips.keys()}
|
|
|
|
if runMode=="New":
|
|
|
|
model8 = pulp.LpProblem("League_Scheduling_Model_--_Assign_EBL_Trips_"+str(thisScenario.id), pulp.LpMinimize)
|
|
|
|
xxx = { (t1,t2,r) : pulp.LpVariable('xxx_'+str(t1)+'_'+str(t2)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for t1 in teams for t2 in teams for r in xxx_rounds }
|
|
toomany = { (t1,r) : pulp.LpVariable('toomany_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpContinuous) for t1 in teams for r in rounds }
|
|
|
|
for (t1,t2,r) in (singleTrips_EBL+trips_ebl) :
|
|
xxx[(t1,t2,r)].cat=pulp.LpInteger
|
|
xxx[(t1,t2,r)].upBound=1
|
|
|
|
home_ebl = { (t1,r) : lpSum([ xxx[(t1,t2,r)] for t2 in teams ]) for t1 in teams for r in xxx_rounds}
|
|
away_ebl = { (t2,r) : lpSum([ xxx[(t1,t2,r)] for t1 in teams ]) for t2 in teams for r in xxx_rounds}
|
|
|
|
print (home_ebl.keys())
|
|
|
|
for t1 in teams:
|
|
for t2 in teams:
|
|
model8+= lpSum([ xxx[(t1,t2,r)]+xxx[(t2,t1,r)] for r in xxx_rounds if r<=17 ]) <= 1
|
|
model8+= lpSum([ xxx[(t1,t2,r)]+xxx[(t2,t1,r)] for r in xxx_rounds if r>=18 ]) <= 1
|
|
|
|
model8+=lpSum([ xxx[(t1,t2,r)] for (t1,t2) in games_ebl for r in xxx_rounds ])
|
|
|
|
# do not visit two teams in doubleweeks which would result in a B2B
|
|
for r in elb_rounds:
|
|
for t in teams:
|
|
lhs1 = [ xxx[(t1,t,r)] for t1 in criticalAvailabilities[r] if t!=t1]
|
|
lhs2= [ xxx[(t2,t,r+1)] for t2 in criticalAvailabilities[r+1] if t!=t2]
|
|
if len(lhs1)*len(lhs2)>0:
|
|
model8+= lpSum( lhs1+lhs2 ) <= 1 + toomany[(t,r)]
|
|
if t in criticalAvailabilities[r] and len(lhs2)>0:
|
|
model8+= home_ebl[(t,r)] + lpSum( lhs2 ) <= 1 + toomany[(t,r)]
|
|
if t in criticalAvailabilities[r+1] and len(lhs1)>0:
|
|
model8+= home_ebl[(t,r+1)] + lpSum( lhs1 ) <= 1 + toomany[(t,r)]
|
|
if t in criticalAvailabilities[r] and t in criticalAvailabilities[r+1] :
|
|
model8+= home_ebl[(t,r)] + home_ebl[(t,r+1)] <= 1 + toomany[(t,r)]
|
|
|
|
for t1 in teams:
|
|
for r in xxx_rounds:
|
|
model8+=xxx[(t1,t1,r)]==0
|
|
# one game a day1
|
|
model8+= home_ebl[(t1,r)] + away_ebl[(t1,r)] ==1
|
|
# print ("one game for ", getTeamById[t1] , " in round ", r, home_ebl[(t1,r)] + away_ebl[(t1,r)] )
|
|
# half of the games played at home
|
|
if len(xxx_rounds) < len(rounds):
|
|
model8+= lpSum ( [ home_ebl[(t1,r)] for r in xxx_rounds ]) == 0.5*len(xxx_rounds)
|
|
|
|
|
|
for (t1,t2) in games_ebl:
|
|
model8+=lpSum([ xxx[(t1,t2,r)] for r in xxx_rounds ]) <=1
|
|
if (t2,t1) in games_ebl and t1<t2:
|
|
model8+=lpSum([ xxx[(t1,t2,r)]+ xxx[(t2,t1,r)] for r in xxx_rounds if r<=17 ]) <=1
|
|
model8+=lpSum([ xxx[(t1,t2,r)]+ xxx[(t2,t1,r)] for r in xxx_rounds if r>17 ]) <=1
|
|
model8+=lpSum([ xxx[(t1,t2,r)]+ xxx[(t2,t1,r)] for r in xxx_rounds if r>=13 and r<=19 ]) <=1
|
|
|
|
# model8+=lpSum([ xxx[(t1,t2,r)] for (t1,t2) in games_ebl for r in xxx_rounds ])
|
|
|
|
# no_travel_elb = [3,27,31]
|
|
# no_travel_elb = [27]
|
|
# no_travel_elb = [ ("AX Armani Exchange Milan", 13 ) , ("AX Armani Exchange Milan", 9 ) , ("Baskonia Vitoria-Gasteiz", 9 ) ,
|
|
# ("Partizan Nis Belgrade", 3 ) , ("ALBA Berlin", 3 ) ,("Crvena Zvezda mts Belgrade", 22) , ("ALBA Berlin", 22 ) ,
|
|
# ("ALBA Berlin", 27 ) ]
|
|
# # no_travel_elb = [ ("AX Armani Exchange Milan", 13 ) , ("AX Armani Exchange Milan", 9 ) , ("Baskonia Vitoria-Gasteiz", 9 ) , ("Partizan Nis Belgrade", 3 ) , ("ALBA Berlin", 3 ) ,("Crvena Zvezda mts Belgrade", 22) , ("ALBA Berlin", 22 ) , ("ALBA Berlin", 27 ), ("Anadolu Efes Istanbul", 27 ) ]
|
|
# no_travel_elb = [ ("AX Armani Exchange Milan", 13 ) , ("AX Armani Exchange Milan", 9 ) , ("Baskonia Vitoria-Gasteiz", 9 ) ,
|
|
# ("Partizan Nis Belgrade", 3 ) , ("ALBA Berlin", 3 ) ,("Crvena Zvezda mts Belgrade", 22) , ("ALBA Berlin", 22 ) ,
|
|
# ("Anadolu Efes Istanbul", 27 ), ("Zalgiris Kaunas", 27 ) ]
|
|
no_travel_elb = []
|
|
for r in elb_rounds:
|
|
for t in teams:
|
|
ss1 = sum ( t_blocked_at[t,r2] for r2 in [r-2,r-1] )
|
|
ss2 = sum ( t_blocked_at[t,r2] for r2 in [r-1,r+2] )
|
|
ss3 = sum ( t_blocked_at[t,r2] for r2 in [r+2,r+3] )
|
|
print (r, ss1,ss2,ss3, getTeamById[t])
|
|
urt = max( t_blocked_at[t,r-2]+t_blocked_at[t,r-1] , t_blocked_at[t,r-1]+t_blocked_at[t,r+2] , t_blocked_at[t,r+2]+t_blocked_at[t,r+3] )
|
|
if urt ==2 :
|
|
print ("DO NOT TRAVEL ")
|
|
no_travel_elb.append((getTeamById[t],r))
|
|
|
|
print ("no_travel_elb",no_travel_elb)
|
|
|
|
travel_elb ={}
|
|
for t in teams:
|
|
# every team travels to other clusters twice
|
|
model8+= lpSum( [travel_to_cluster[ (t2,r,g)] for (t2,r,g) in possTrips.keys() if t==t2 ])== 2
|
|
for r in elb_rounds:
|
|
travel_elb[(t,r)] = lpSum( [travel_to_cluster[ (t2,r2,g)] for (t2,r2,g) in possTrips.keys() if t==t2 and r==r2 ])
|
|
print ("TRAVEL 1 ", t, r, travel_elb[(t,r)])
|
|
model8+= away_ebl[(t,r)] + away_ebl[(t,r+1)] <= 1 + travel_elb[(t,r)]
|
|
model8+= lpSum([ xxx[(t1,t,r)] for t1 in far_teams[t] ]) <= travel_elb[(t,r)]
|
|
model8+= lpSum([ xxx[(t1,t,r+1)] for t1 in far_teams[t] ]) <= travel_elb[(t,r)]
|
|
|
|
# model8+= travel_elb[(t,9)] + travel_elb[(t,13)] == 1
|
|
# model8+= travel_elb[(t,18)] + travel_elb[(t,22)] == 1
|
|
|
|
model8+=lpSum([ travel_elb[(t,r)] for r in elb_rounds if r<=17 ]) ==1
|
|
|
|
|
|
for (t,r) in no_travel_elb :
|
|
model8+= travel_elb[(getTeamIdByName[t],r)] ==0
|
|
print ("no travel", getTeamIdByName[t],t,r)
|
|
|
|
for (t2,r,g) in travel_to_cluster.keys():
|
|
model8+= travel_to_cluster[ (t2,r,g)] <= lpSum( [xxx[(t1,t2,r)] for t1 in getTeamsOfNeighbor[g] ] )
|
|
model8+= travel_to_cluster[ (t2,r,g)] <= lpSum( [xxx[(t1,t2,r+1)] for t1 in getTeamsOfNeighbor[g] ] )
|
|
|
|
for (t2,r,g) in fixed_travels:
|
|
print ( "fixed_travel " , t2,r,g)
|
|
model8 += travel_to_cluster[(getTeamIdByName[t2],r,getConfId[g])]==1
|
|
|
|
|
|
# model8 += home_ebl [(getTeamIdByName["FC Bayern Munich"],24)] + home_ebl[(getTeamIdByName["FC Bayern Munich"],25)] <= 1
|
|
# model8 += home_ebl [(getTeamIdByName["ALBA Berlin"],31)] + home_ebl [(getTeamIdByName["ALBA Berlin"],32)] >=1
|
|
# model8 += home_ebl [(getTeamIdByName["Maccabi FOX Tel Aviv"],6)] + home_ebl [(getTeamIdByName["Maccabi FOX Tel Aviv"],7)] >=1
|
|
# model8 += home_ebl [(getTeamIdByName["Maccabi FOX Tel Aviv"],10)] ==1
|
|
# model8 += home_ebl [(getTeamIdByName["Maccabi FOX Tel Aviv"],11)] ==1
|
|
# model8 += home_ebl [(getTeamIdByName["Zalgiris Kaunas"],21)] ==1
|
|
# model8 += home_ebl [(getTeamIdByName["AS Monaco"],4)] ==1
|
|
# model8 += home_ebl [(getTeamIdByName["AS Monaco"],6)]+ home_ebl [(getTeamIdByName["AS Monaco"],7)] >=1
|
|
|
|
for (t1,t2,r) in xxx.keys():
|
|
if t_blocked_at[(t1,r)] and getTeamById[t2]!="ALBA Berlin" and False:
|
|
model8 += xxx[(t1,t2,r)]==0
|
|
|
|
# TEAMS;5;120
|
|
# TEAMSROUNDS
|
|
# ROUNDS;10
|
|
# GROUPS
|
|
|
|
|
|
|
|
# model8+=lpSum([ xxx[(t1,t2,r)] for t1 in teams for t2 in teams for r in xxx_rounds ])
|
|
# model8.solve(XPRESS(msg=1,maxSeconds = 160, options=["THREADS=12"], keepFiles=True))
|
|
# for r in xxx_rounds :
|
|
# print ("Round ", r)
|
|
# for (t1,t2) in games_ebl :
|
|
# if xxx[(t1,t2,r)].value()>0.5:
|
|
# print (" " ,getTeamById[t1], " - " , getTeamById[t2] )
|
|
# exit(0)
|
|
|
|
|
|
|
|
blockvioTrips_ebl = lpSum( [travel_to_cluster[ (t2,r,g)] for (t2,r,g) in possTrips.keys() if t_blocked_at[(t1,r-1)] and t_blocked_at[(t1,r+2)]])
|
|
blockvios_ebl=lpSum([ xxx[(t1,t2,r)] for (t1,t2,r) in xxx.keys() if t_blocked_at[(t1,r)] ])
|
|
usegames_ebl=lpSum([ xxx[(t1,t2,r)] for (t1,t2,r) in xxx.keys() if (t1,t2) in games_ebl ])
|
|
toomanyaways = lpSum([ toomany[(t,r)] for (t,r) in toomany.keys() ])
|
|
|
|
# model8+= usegames_ebl ==126
|
|
model8+= usegames_ebl == len(teams) /2*len(xxx_rounds)
|
|
|
|
model8+= blockvios_ebl + blockvioTrips_ebl + toomanyaways - 0.1*lpSum([ xxx[(t1,t2,r)] for (t1,t2) in games_ebl for r in xxx_rounds ])
|
|
|
|
if solver == "CBC":
|
|
model8.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 240, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model8.solve(GUROBI( TimeLimit=240,msg=1))
|
|
else:
|
|
model8.solve(XPRESS(msg=1,maxSeconds = 160, options=["THREADS=12"], keepFiles=True))
|
|
|
|
for r in xxx_rounds :
|
|
print ("Round ", r)
|
|
for (t1,t2) in games_ebl :
|
|
if xxx[(t1,t2,r)].value()>0.5:
|
|
print (" ",xxx[(t1,t2,r)].value() ,getTeamById[t1], " - " , getTeamById[t2] )
|
|
|
|
|
|
|
|
fixed_travels = [ ( getTeamById[t2],r, getNameOfNeighbor[g]) for (t2,r,g) in possTrips.keys() if travel_to_cluster[(t2,r,g)].value()>0.1 ]
|
|
|
|
print ("fixed_travels=", fixed_travels)
|
|
|
|
for t1 in teams:
|
|
model2+= lpSum ( [ homeInRound[(t1,r)] for r in xxx_rounds ]) == 0.5*len(xxx_rounds)
|
|
|
|
tooFarViolation = { (t1,r) : pulp.LpVariable('tooFarViolation_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 10, cat = pulp.LpContinuous) for t1 in teams for r in xxx_rounds }
|
|
|
|
for (t,r) in travel_elb.keys():
|
|
if travel_elb[(t,r)].value()>=0.9:
|
|
print ("TRAVEL ",r, getTeamById[t], travel_elb[(t,r)].value())
|
|
else:
|
|
for t1 in far_teams[t]:
|
|
model2+= x_round[(t1,t,r)]==0
|
|
model2+= x_round[(t1,t,r+1)]== 0
|
|
model2+= x_round[(t1,t,r+1)]<= tooFarViolation[(t,r+1)]
|
|
model2+= awayInRound[(t,r)]+awayInRound[(t,r+1)] <=1
|
|
|
|
print (len (travel_elb.keys()))
|
|
|
|
|
|
specialObjectives = 1000 * lpSum([ tooFarViolation[(t,r)] for (t,r) in tooFarViolation.keys() ])
|
|
|
|
|
|
for (t,r) in toomany.keys():
|
|
if toomany[(t,r)].value()>0.9:
|
|
print ("too many " ,r, " ", getTeamById[t])
|
|
|
|
|
|
for (t2,r,g) in fixed_travels:
|
|
model2+= lpSum( [x_round[(t1,getTeamIdByName[t2],r)] for t1 in getTeamsOfNeighbor[getConfId[g]] ] ) ==1
|
|
model2+= lpSum( [x_round[(t1,getTeamIdByName[t2],r+1)] for t1 in getTeamsOfNeighbor[getConfId[g]] ] ) ==1
|
|
|
|
for r in xxx_rounds:
|
|
print ()
|
|
print ("ROUND ", r)
|
|
for (t1,t2) in games_ebl:
|
|
if xxx[(t1,t2,r)].value()>0.1:
|
|
bcked = "#### " if t_blocked_at[(t1,r)] else " - "
|
|
print (getTeamById[t1] , bcked , getTeamById[t2] , " ", xxx[(t1,t2,r)].value())
|
|
model2+= x_round[(t1,t2,r)]==1
|
|
|
|
print (blockvios_ebl.value())
|
|
print (blockvioTrips_ebl.value())
|
|
print (toomanyaways.value())
|
|
|
|
else:
|
|
print ("++++++++++ IMPROVE SOLUTION ++++++++++")
|
|
for t1 in teams:
|
|
# half of the games played at home
|
|
model2+= lpSum ( [ homeInRound[(t1,r)] for r in xxx_rounds ]) == 0.5*len(xxx_rounds)
|
|
|
|
travel_elb ={}
|
|
for t in teams:
|
|
# every team travels to other clusters twice
|
|
model2+= lpSum( [travel_to_cluster[ (t2,r,g)] for (t2,r,g) in possTrips.keys() if t==t2 ])== 2
|
|
for r in elb_rounds:
|
|
travel_elb[(t,r)] = lpSum( [travel_to_cluster[ (t2,r2,g)] for (t2,r2,g) in possTrips.keys() if t==t2 and r==r2 ])
|
|
print ("TRAVEL 1 ", t, r, travel_elb[(t,r)])
|
|
model2+= awayInRound[(t,r)] + awayInRound[(t,r+1)] <= 1 + travel_elb[(t,r)]
|
|
model2+= lpSum([ x_round[(t1,t,r)] for t1 in far_teams[t] ]) <= travel_elb[(t,r)]
|
|
model2+= lpSum([ x_round[(t1,t,r+1)] for t1 in far_teams[t] ]) <= travel_elb[(t,r)]
|
|
|
|
for (t2,r,g) in travel_to_cluster.keys():
|
|
model2+= travel_to_cluster[ (t2,r,g)] <= lpSum( [x_round[(t1,t2,r)] for t1 in getTeamsOfNeighbor[g] ] )
|
|
model2+= travel_to_cluster[ (t2,r,g)] <= lpSum( [x_round[(t1,t2,r+1)] for t1 in getTeamsOfNeighbor[g] ] )
|
|
|
|
if mathModelName=="UEFA NL" :
|
|
|
|
if thisSeason.name=="2024" :
|
|
|
|
clashes_raw =[]
|
|
clashes_raw +=['ARM-AZE','UKR-RUS','GIB-ESP','KOS-BIH','KOS-SRB','KOS-RUS','UKR-BLR']
|
|
# clashes_raw +=['SRB-MKD','SRB-BIH','SRB-ALB','SRB-CRO','MKD-ALB','MKD-GRE','BIH-CRO','TUR-CYP','TUR-ARM','KOS-ARM','KOS-AZE','KOS-BLR','KOS-CYP','KOS-GEO','KOS-GRE','KOS-ISR','KOS-KAZ','KOS-MDA','KOS-ROU','KOS-RUS','KOS-SVK','KOS-ESP','KOS-UKR']
|
|
clashes = [ (c[:3],c[4:]) for c in clashes_raw if c[:3] in countries and c[4:] in countries ]
|
|
print ("clashes", clashes)
|
|
|
|
print ( thisSeason.name=="2024")
|
|
|
|
american_teams = [t for t in teams if t_lon[t] <=-20]
|
|
european_teams = [t for t in teams if t_lon[t] >-20]
|
|
|
|
print ("american_teams", american_teams)
|
|
print ("european_teams", european_teams)
|
|
|
|
usedWeekdays = set([getWeekDay[d] for d in days])
|
|
# print (getNiceDay[d['id']], getWeekDay[d['id']])
|
|
|
|
# print (t_conference)
|
|
|
|
day3pairs =[ (d1,d2) for d1 in days for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] ==datetime.timedelta(days=3) ]
|
|
print (day3pairs)
|
|
|
|
# possGames_UEFA = [(t1,t2) for t1 in teams for t2 in teams if t1!=t2 and t_conference[t1].name[0]==t_conference[t2].name[0]]
|
|
possGames_UEFA = [(t1,t2) for t1 in teams for t2 in teams if t1!=t2 and t_conference[t1].name[0]==t_conference[t2].name[0] and not (t_country[t1],t_country[t2]) in clashes and not (t_country[t2],t_country[t1]) in clashes ]
|
|
nopossGames_UEFA = [(t1,t2) for t1 in teams for t2 in teams if not (t1,t2) in possGames_UEFA ]
|
|
|
|
# possGames_UEFA = [(t1,t2) for t1 in teams for t2 in teams if t1!=t2 and t_conference[t1].name[0]==t_conference[t2].name[0]]
|
|
# nopossGames_UEFA = [(t1,t2) for t1 in teams for t2 in teams if t1==t2 or t_conference[t1].name[0]!=t_conference[t2].name[0]]
|
|
|
|
print ("")
|
|
print (len(possGames_UEFA), "possGames_UEFA")
|
|
print (len(nopossGames_UEFA), "nopossGames_UEFA")
|
|
print ("")
|
|
|
|
# for (t1,t2) in possGames_UEFA:
|
|
# print (getTeamById[t1] , " might play ", getTeamById[t2] , t_conference[t1].name[0] , t_conference[t2].name[0])
|
|
|
|
for (t1,t2) in nopossGames_UEFA:
|
|
for rd in roundDays:
|
|
if (t1,t2,rd) in x.keys():
|
|
setUB(x[(t1,t2,rd)],0)
|
|
|
|
# model2 += lpSum([x[(t1,t2,rd)] for rd in roundDays]) == 0
|
|
print (getTeamById[t1] , " will not play ", getTeamById[t2] , t_conference[t1].name[0] , t_conference[t2].name[0])
|
|
|
|
|
|
for (t1,t2) in possGames_UEFA:
|
|
if t1<t2 and t_conference[t1].name[0]!="C":
|
|
model2 += lpSum([x[(t1,t2,rd)] + x[(t2,t1,rd)] for rd in roundDays]) <= 1
|
|
print (getTeamById[t1] , " might play ", getTeamById[t2] , t_conference[t1].name[0] , t_conference[t2].name[0])
|
|
|
|
all_american_games_A = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in american_teams and t2 in american_teams and t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A"]
|
|
all_american_games_B = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in american_teams and t2 in american_teams and t_conference[t1].name[0]=="B" and t_conference[t2].name[0]=="B"]
|
|
|
|
if len(all_american_games_A)>0:
|
|
model2 += lpSum([x[(t1,t2,(r,d))] for (t1,t2,(r,d)) in all_american_games_A ]) ==12
|
|
if len(all_american_games_B)>0:
|
|
model2 += lpSum([x[(t1,t2,(r,d))] for (t1,t2,(r,d)) in all_american_games_B ]) == 4
|
|
|
|
for (t1,t2,(r,d)) in all_american_games_A:
|
|
if r in [1,2,7,8]:
|
|
model2 += x[(t1,t2,(r,d))]==0
|
|
|
|
for (t1,t2,(r,d)) in all_american_games_B:
|
|
if r in [3,4,5,6,7,8]:
|
|
model2 += x[(t1,t2,(r,d))]==0
|
|
|
|
|
|
|
|
|
|
for t in teams:
|
|
if not getTeamById[t] in ["Iceland", "Faroe Islands"]:
|
|
for rn in [3,4,5,6,7,8]:
|
|
model2 += break3InRound[(t,rn)]== 0
|
|
# if getTeamById[t]=="Ukraine":
|
|
# model2 += awayInRound[(t1,7)]== 1
|
|
# model2 += awayInRound[(t1,8)]== 1
|
|
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for t2 in teams for rd in roundDays if t_conference[t]!=t_conference[t2]]) == 4
|
|
model2 += lpSum([home[(t,d)] for d in days ]) == 4
|
|
|
|
for (d1,d2) in day3pairs:
|
|
model2 += home[(t,d1)]+away[(t,d1)] == home[(t,d2)]+ away[(t,d2)]
|
|
|
|
if t_conference[t].name[0]=="A" :
|
|
for pp in ["A1","A2"]:
|
|
model2 += lpSum([x[(t,t2,rd)] + x[(t2,t,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) == 4
|
|
# 2 home matches against pot 1, 2 home matches against pot 2 and 2 away matches against pot 1, 2 away matches against pot 2
|
|
model2 += lpSum([x[(t,t2,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) == 2
|
|
|
|
# if t in american_teams:
|
|
# model2 += lpSum([(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys()
|
|
|
|
# if t1 in american_teams and t2 in american_teams and r in [3,4,5,6]] [x[(t,t2,rd)] + x[(t2,t,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) == 4
|
|
|
|
|
|
|
|
# model2 += lpSum([x[(t,t2,rd)] + x[(t2,t,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) >= 2
|
|
|
|
# For league B, the 16 European teams are split in 4 pots and the last four CONMEBOL teams (VEN, PAR, ECU, BOL) join them.
|
|
# The swiss system is still used and each team must play two teams from each pot (8MDs).
|
|
# For the CONMEBOL teams, two different splits are possible: one team per pot or 2 teams in the two first pots.
|
|
# Could you please try both options and see which one is the most convenient?
|
|
# In addition, the CONMEBOL teams must play each other but only over one international window
|
|
# (let's say in September 2024) as they don't have enough opponents to play 4 MDs against each other.
|
|
if t_conference[t].name[0]=="B" :
|
|
for pp in ["B1","B2","B3","B4"]:
|
|
model2 += lpSum([x[(t,t2,rd)] + x[(t2,t,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) == 2
|
|
# 1 home match against one team from each pot and 1 away match against one team from each pot
|
|
model2 += lpSum([x[(t,t2,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) == 1
|
|
# model2 += lpSum([x[(t,t2,rd)] + x[(t2,t,rd)] for rd in roundDays for t2 in teams if t_conference[t2].name==pp]) >= 1
|
|
|
|
# For league C, the format is different and it is not a swiss system anymore.
|
|
# A proposal would be to have 4 groups of 4 teams but to pair 2 groups together (1A and 1B together, 2A and 2B together).
|
|
# The four teams from one group (1A) would play home and away the four teams from the other group (1B).
|
|
# In the excel table, you will see the group proposal.
|
|
|
|
for (c1,c2) in [("C1A","C1B"), ("C2A","C2B")]:
|
|
if t_conference[t].name==c1:
|
|
for t2 in teams :
|
|
if t_conference[t2].name==c2:
|
|
model2 += lpSum([x[(t,t2,rd)] for rd in roundDays]) == 1
|
|
model2 += lpSum([x[(t2,t,rd)] for rd in roundDays]) == 1
|
|
model2 += lpSum([x[(t,t2,(r,d))] + x[(t2,t,(r,d))] for (r,d) in roundDays if r<=4]) == 1
|
|
|
|
|
|
# use every weekday at least once:
|
|
# for wd in usedWeekdays:
|
|
# model2 += lpSum([home[(t,d)] + away[(t,d)] for d in days if getWeekDay[d]==wd ]) >= 1
|
|
|
|
# for t2 in teams:
|
|
# if gameCntr[(t,t2)]+gameCntr[(t2,t)]>0:
|
|
# print("adding" , t , t2)
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for rd in roundDays if t!=t2]) <= 1
|
|
# if t_conference[t].name[0]!=t_conference[t2].name[0]:
|
|
# model2 += lpSum([x[(t,t2,rd)] for rd in roundDays if t!=t2]) == 0
|
|
# # print (getTeamById[t] , " does not play ", getTeamById[t2] , t_conference[t].name[0] , t_conference[t2].name[0] )
|
|
|
|
# # else:
|
|
# # print("ignoring" , t , t2)
|
|
|
|
# print ("TESTING")
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=40,msg=1))
|
|
# print ("TESTING DONE")
|
|
|
|
|
|
print (t_conference)
|
|
|
|
|
|
# for t in american_teams:
|
|
# for (r,d) in getRoundDaysByRound[3]:
|
|
# if t!= american_teams[0]:
|
|
# model2 += home[(t,d)]+away[(t,d)] == home[(american_teams[0],d)]+away[(american_teams[0],d)]
|
|
|
|
# for r in [3,4,5,6]:
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for t2 in american_teams for rd in getRoundDaysByRound[r] if t!=t2]) == 1
|
|
# for r in [1,2,7,8]:
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for t2 in american_teams for rd in getRoundDaysByRound[r] if t!=t2]) == 0
|
|
|
|
# league_A_games = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A" ]
|
|
# league_B_games = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="B" and t_conference[t2].name[0]=="B" ]
|
|
# league_C_games = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="C" and t_conference[t2].name[0]=="C" ]
|
|
league_A1_games = set([(t1,t2,r) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A" if r in [3,4,5,6] ])
|
|
league_A_games = set([(t1,t2,r) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A" ])
|
|
league_B_games = set([(t1,t2,r) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="B" and t_conference[t2].name[0]=="B" ])
|
|
league_B1_games = set([(t1,t2,r) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="B" and t_conference[t2].name[0]=="B" if r <=4 ])
|
|
league_C_games = set([(t1,t2,r) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="C" and t_conference[t2].name[0]=="C" ])
|
|
|
|
# all_american_games = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in american_teams and t2 in american_teams and r in [3,4,5,6]]
|
|
# half_american_games = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in american_teams != t2 in american_teams and r in [1,2,7,8]]
|
|
# all_european_games1 = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in european_teams and t2 in european_teams and r in [1,2,3,4]]
|
|
# all_european_games2 = [(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t1 in european_teams and t2 in european_teams and r in [5,6,7,8]]
|
|
|
|
if runMode=='New':
|
|
|
|
# print (len(league_A_games))
|
|
# print (len(league_B_games))
|
|
# print (len(league_C_games))
|
|
|
|
|
|
optIterations = []
|
|
if len(league_C_games)>0:
|
|
optIterations+=[(league_C_games, " league_C_games ","rounds")]
|
|
optIterations+=[(league_A1_games, " league_A1_games ","rounds" )]
|
|
optIterations+=[(league_A_games, " league_A_games " ,"rounds")]
|
|
optIterations+=[(league_B1_games, " league_B1_games " ,"rounds")]
|
|
optIterations+=[(league_B_games, " league_B_games " ,"rounds")]
|
|
else:
|
|
league_A1_games = set([(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A" if r in [3,4,5,6] ])
|
|
league_A_games = set([(t1,t2,(r,d)) for (t1,t2,(r,d)) in x.keys() if t_conference[t1].name[0]=="A" and t_conference[t2].name[0]=="A" ])
|
|
optIterations+=[(league_A1_games, " league_A1_games " ,"days")]
|
|
optIterations+=[(league_A_games, " league_A_games " , "days")]
|
|
|
|
|
|
# for gms,txt in [ ( all_american_games, " ALL AMERICAN " ), ( half_american_games, " HALF AMERICAN " ) , ( all_european_games1, " all_european_games1 " ) , ( all_european_games2, " all_european_games2 " ) ] :
|
|
# for gms,txt in [ ( all_american_games, " ALL AMERICAN " ), ( all_european_games1, " all_european_games1 " ) , ( all_european_games2, " all_european_games2 " ) ] :
|
|
# for gms,txt in [ ( all_american_games, " ALL AMERICAN " ) ] :
|
|
for gms,txt,gran in optIterations :
|
|
print ("!!!!!!! PRE RUN "+txt+"!!!!!!")
|
|
print (len(gms))
|
|
for rr in gms:
|
|
if gran=="rounds":
|
|
makeIntVar(x_round[rr])
|
|
else:
|
|
makeIntVar(x[rr])
|
|
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=0.1, TimeLimit=240,msg=1))
|
|
else:
|
|
model2.solve(XPRESS(msg=1,maxSeconds = 140, options=["THREADS=12"], keepFiles=True))
|
|
|
|
for rr in gms:
|
|
if gran=="rounds":
|
|
model2+= x_round[rr] ==getVal(x_round[rr])
|
|
if getVal(x_round[rr]) >0.1:
|
|
print (rr , getVal(x_round[rr]))
|
|
else:
|
|
model2+= x[rr] ==getVal(x[rr])
|
|
if getVal(x[rr]) >0.1:
|
|
print (rr , getVal(x[rr]))
|
|
# for t in european_teams:
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for t2 in american_teams for rd in roundDays ]) >= 1
|
|
# model2 += lpSum([x[(t,t2,rd)] +x[(t2,t,rd)] for t2 in american_teams for rd in roundDays ]) <= 2
|
|
|
|
|
|
else :
|
|
|
|
# model2+=gamesTooCloseTotal==0
|
|
specialObjectives+=1000*gamesTooCloseTotal
|
|
|
|
# closeTeams_UEFA = { "Kazakhstan" : [ "Andorra", "England","Faroe Islands","Gibraltar", "Iceland","Malta", "Northern Ireland","Portugal","Republic of Ireland","Scotland","Spain","Wales" ] ,
|
|
closeTeams_UEFA = { "Kazakhstan" : [ "Andorra", "England","France","Faroe Islands","Gibraltar", "Iceland","Malta",
|
|
"Northern Ireland", "Portugal","Republic of Ireland","Scotland","Spain","Wales" ] ,
|
|
"Azerbaijan" : ["Gibraltar", "Iceland", "Portugal"],
|
|
"Iceland" : ["Armenia", "Cyprus", "Georgia", "Israel"] }
|
|
|
|
# Label to represent both teams (Kazakstan/Modolva - Cyprus/Estonia) to carry both constrains of each pair.
|
|
# closeTeams_UEFA = { "KAZ/MDA 1" : [ "Andorra", "England","France","Faroe Islands","Gibraltar", "Iceland","Malta", "Northern Ireland","Portugal","Republic of Ireland","Scotland","Spain","Wales" ] ,
|
|
# "KAZ/MDA 2" : [ "Andorra", "England","France","Faroe Islands","Gibraltar", "Iceland","Malta", "Northern Ireland","Portugal","Republic of Ireland","Scotland","Spain","Wales" ] ,
|
|
# "Azerbaijan" : ["Gibraltar", "Iceland", "Portugal"],
|
|
# "Iceland" : ["Armenia", "CYP/EST 1", "CYP/EST 2", "Georgia", "Israel"] }
|
|
|
|
# for tn1 in closeTeams_UEFA.keys():
|
|
# for tn2 in closeTeams_UEFA[tn1]:
|
|
# t1 = getTeamIdByName[tn1]
|
|
# t2 = getTeamIdByName[tn2]
|
|
# print (t1, t2 , t_conference[t1] ,t_conference[t2] , t_conference[t1]==t_conference[t2] , tn1, tn2 )
|
|
|
|
closeTeams_UEFA = [ (getTeamIdByName[tn1],getTeamIdByName[tn2]) for tn1 in closeTeams_UEFA.keys() for tn2 in closeTeams_UEFA[tn1] if t_conference[getTeamIdByName[tn1]]==t_conference[getTeamIdByName[tn2]] ]
|
|
print ("closeTeams_UEFA", [(getTeamById[t1] ,getTeamById[t2]) for (t1,t2) in closeTeams_UEFA])
|
|
|
|
# for (tn1,tn2) in closeTeams_UEFA:
|
|
# t1 = getTeamById[tn1]
|
|
# t2 = getTeamById[tn2]
|
|
# print (t1, t2 , t_conference[tn1] ,t_conference[tn2] , t_conference[tn1]==t_conference[tn2] , tn1, tn2 )
|
|
|
|
|
|
# 1234 56
|
|
two_starter_uefa= [5]
|
|
mid_starter_uefa= [2,3]
|
|
three_starter_uefa= [1]
|
|
|
|
two_starter_uefa= [1,3,5,7,9]
|
|
mid_starter_uefa= []
|
|
three_starter_uefa= []
|
|
# for t in teams:
|
|
# if noPlayRounds[t] == [7,8]:
|
|
# two_starter_uefa= [7,9]
|
|
# mid_starter_uefa= [2,5]
|
|
# three_starter_uefa= [1,4]
|
|
|
|
print ("two_starter_uefa", two_starter_uefa)
|
|
print ("three_starter_uefa", three_starter_uefa)
|
|
|
|
# TODO
|
|
# no back to back in md 3 and 4
|
|
# no break in md 5/6
|
|
# max 3 rest days between games
|
|
|
|
day3pairs =[ (d1,d2) for d1 in days for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] ==datetime.timedelta(days=3) ]
|
|
day34pairs ={ d1 : [d2 for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] in [datetime.timedelta(days=di) for di in [3,4]]] for d1 in days }
|
|
day345pairs ={ d1 : [d2 for d2 in days if getDateTimeDay[d2]-getDateTimeDay[d1] in [datetime.timedelta(days=di) for di in [3,4,5]]] for d1 in days }
|
|
|
|
closeDays_UEFA = two_starter_uefa+mid_starter_uefa+three_starter_uefa
|
|
closeDays_UEFA = []
|
|
|
|
if "3DaysForDistantTeams" in special_wishes_active:
|
|
sw_type="3DaysForDistantTeams"
|
|
for (t1,t2) in closeTeams_UEFA:
|
|
# model2 += lpSum( [ x[t1,t2,rd] + x[t2,t1,rd] for rd in getRoundDaysByRound[4]] ) ==1
|
|
# model2 += lpSum( [ x[t1,t2,rd] + x[t2,t1,rd] for rd in getRoundDaysByRound[1]] ) ==1
|
|
for (d1,d2) in day3pairs:
|
|
specialWishVio[(sw_type,t1,t2,d1)]= pulp.LpVariable('specialWishVio_'+sw_type+'_'+str(t1)+"_"+str(t2)+"_"+str(d1), lowBound=0, cat=pulp.LpContinuous)
|
|
specialWishItems[sw_type].append((t1,t2,d1))
|
|
for t3 in teams:
|
|
if t_conference[t1]==t_conference[t3] and not t3 in [t1,t2]:
|
|
print ("taking care of " , getTeamById[t3] , "'s trip to ", getTeamById[t1] , " and ", getTeamById[t2] )
|
|
model2 += lpSum( [ x[t,t3,rd] for t in [t1,t2] for rd in getRoundDaysByDay[d1]+getRoundDaysByDay[d2] ] ) <=1 + specialWishVio[(sw_type,t1,t2,d1)]
|
|
model2 += home[t1,d1] + lpSum([x[t2,t1, rd] for rd in getRoundDaysByDay[d2]]) <=1 + specialWishVio[(sw_type,t1,t2,d1)]
|
|
model2 += home[t1,d2] + lpSum([x[t2,t1, rd] for rd in getRoundDaysByDay[d1]]) <=1 + specialWishVio[(sw_type,t1,t2,d1)]
|
|
model2 += home[t2,d1] + lpSum([x[t1,t2, rd] for rd in getRoundDaysByDay[d2]]) <=1 + specialWishVio[(sw_type,t1,t2,d1)]
|
|
model2 += home[t2,d2] + lpSum([x[t1,t2, rd] for rd in getRoundDaysByDay[d1]]) <=1 + specialWishVio[(sw_type,t1,t2,d1)]
|
|
specialObjectives += 1000*lpSum([ sw_prio[sw_type]* specialWishVio[(sw_type,t1,t2,d1)] for (t1,t2,d1) in specialWishItems[sw_type] ])
|
|
|
|
|
|
# for (t1,t2) in closeTeams_UEFA:
|
|
# for rn in closeDays_UEFA:
|
|
# for t3 in teams:
|
|
# if t_conference[t1]==t_conference[t3] and not t3 in [t1,t2]:
|
|
# # print ("taking care of " , getTeamById[t3] , "'s trip to ", getTeamById[t1] , " and ", getTeamById[t2] )
|
|
# model2 += lpSum( [ x[t1,t3,d] + x[t2,t3,d] for d in getRoundDaysByRound[rn]+getRoundDaysByRound[rn+1] ] ) <=1
|
|
|
|
# # print ("I don't care about " , getTeamById[t1] , "'s trip to ", getTeamById[t2])
|
|
# # print ("taking care of " , getTeamById[t1] , "'s trip to ", getTeamById[t2])
|
|
# model2 += homeInRound[(t1,rn)] + lpSum([x[t2,t1, rd] for rd in getRoundDaysByRound[rn+1]]) <=1
|
|
# model2 += homeInRound[(t1,rn+1)] + lpSum([x[t2,t1, rd] for rd in getRoundDaysByRound[rn]]) <=1
|
|
# # print ("taking care of " , getTeamById[t2] , "'s trip to ", getTeamById[t1])
|
|
# # if getTeamById[t2]!="France":
|
|
# model2 += homeInRound[(t2,rn)] + lpSum([x[t1,t2, rd] for rd in getRoundDaysByRound[rn+1]]) <=1
|
|
# model2 += homeInRound[(t2,rn+1)] + lpSum([x[t1,t2, rd] for rd in getRoundDaysByRound[rn]]) <=1
|
|
# # else:
|
|
# # if rn>1:
|
|
# # model2 += homeInRound[(t2,rn-1)] + lpSum([x[t1,t2, rd] for rd in getRoundDaysByRound[rn]]) + homeInRound[(t2,rn+1)] <=2
|
|
|
|
print ("getRoundDaysByRound", getRoundDaysByRound)
|
|
|
|
conferences6 = [c for c in Conference.objects.filter(scenario=s2,regional=False) if len(c.teams.filter(active=True))==6]
|
|
conferences5 = [c for c in Conference.objects.filter(scenario=s2,regional=False) if len(c.teams.filter(active=True))==5]
|
|
conferences4 = [c for c in Conference.objects.filter(scenario=s2,regional=False) if len(c.teams.filter(active=True))==4]
|
|
conferences3 = [c for c in Conference.objects.filter(scenario=s2,regional=False) if len(c.teams.filter(active=True))==3]
|
|
|
|
# print ("day34pairs",day34pairs)
|
|
# print (conferences4)
|
|
# print ("confs 3 " , len(conferences3))
|
|
# print ("confs 4 " , len(conferences4))
|
|
# print ("confs 5 " , len(conferences5))
|
|
# print ("confs 6 " , len(conferences6))
|
|
|
|
# alltms =set([])
|
|
|
|
c4= {(c.id,d) : pulp.LpVariable('c4_'+str(c)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for c in conferences4 for d in days}
|
|
c5= {(c.id,d) : pulp.LpVariable('c5_'+str(c)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for c in conferences5 for d in days}
|
|
c6= {(c.id,d) : pulp.LpVariable('c6_'+str(c)+'_'+str(d), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for c in conferences6 for d in days}
|
|
|
|
|
|
travelControl_UEFA= False
|
|
travelControl_UEFA= True
|
|
dontPlayOnGamesList_UEFA= ["2022-06-04", "2022-06-05", "2022-06-08", "2022-06-11", "2022-06-12"]
|
|
if runMode!='Improve':
|
|
dontPlayOnGamesList_UEFA+= ["2022-06-02"]+ ["2022-06-13"] + ["2022-06-06","2022-06-09"]
|
|
dontPlayOnGamesList_UEFA = [ parse(dd) for dd in dontPlayOnGamesList_UEFA ]
|
|
print("dontPlayOnGamesList_UEFA",dontPlayOnGamesList_UEFA)
|
|
dontPlayOnGamesList_UEFA = [ getDayByDateTime[dd] for dd in dontPlayOnGamesList_UEFA if dd in getDayByDateTime.keys()]
|
|
print("dontPlayOnGamesList_UEFA",dontPlayOnGamesList_UEFA)
|
|
if travelControl_UEFA :
|
|
for c in conferences4:
|
|
cteams= c.teams.filter(active=True)
|
|
# print ("checking group" , c )
|
|
for t in cteams:
|
|
# print ("checking team" , t )
|
|
for (t1,t2) in closeTeams_UEFA:
|
|
if t.id==t1:
|
|
for d1 in sorted(dontPlayOnGamesList_UEFA ):
|
|
model2 += c4[(t_conference[t1].id,d1)] == 0
|
|
print (c.name , " cannot play on ", d1 , " " , getNiceDay[d1])
|
|
|
|
for c in conferences3+conferences4:
|
|
cteams= c.teams.filter(active=True)
|
|
for t1 in cteams:
|
|
for t2 in cteams:
|
|
if t2.id < t1.id:
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[3]+getRoundDaysByRound[4] ]) <=1
|
|
|
|
forbidBackToBack = True
|
|
|
|
# when are the next games allowed to be played
|
|
compNextGames = { 1:[4,5], 2:[5,6], 3:[6,7],
|
|
4:[7,8,9], 5:[8,9,10], 6:[9,10],
|
|
7:[10,11,12],
|
|
8:[11,12], 9:[12,13], 10:[13],
|
|
14:[17,18], 15:[18,19], 16:[19],
|
|
}
|
|
|
|
if "forbid4DaysOff" in special_wishes_active :
|
|
compNextGames[4]=[7,8]
|
|
compNextGames[5]=[8,9]
|
|
compNextGames[7]=[10,11]
|
|
|
|
if runMode!='Improve':
|
|
compNextGames[14]=[17]
|
|
compNextGames[15]=[18]
|
|
|
|
if "3RestDaysBetweenMD2andMD3" in special_wishes_active:
|
|
compNextGames[4]=[8]
|
|
compNextGames[5]=[9]
|
|
compNextGames[6]=[10]
|
|
|
|
for c in conferences4:
|
|
cteams= c.teams.filter(active=True)
|
|
t1 = cteams.first()
|
|
for t2 in cteams:
|
|
# no b2b between rounds 3 and 4
|
|
# if t2.id != t1.id :
|
|
# model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[3]+getRoundDaysByRound[4] ]) <=1
|
|
for d1 in days:
|
|
model2 += home[(t2.id,d1)]+away[(t2.id,d1)] == c4[(c.id,d1)]
|
|
# adjust pattern abcbca
|
|
# for t1 in cteams:
|
|
# for t2 in cteams:
|
|
# if t1.id != t2.id:
|
|
# model2 += lpSum( [ x[t1.id,t2.id,d] for d in getRoundDaysByRound[2]]) == lpSum( [ x[t2.id,t1.id,d] for d in getRoundDaysByRound[4]])
|
|
# model2 += lpSum( [ x[t1.id,t2.id,d] for d in getRoundDaysByRound[3]]) == lpSum( [ x[t2.id,t1.id,d] for d in getRoundDaysByRound[5]])
|
|
# for (d1,d2) in day3pairs:
|
|
# if getRoundByDay[d1]>=5:
|
|
# model2 += c4[(c.id,d1)] == c4[(c.id,d2)]
|
|
for di in compNextGames.keys():
|
|
model2 += c4[(c.id,daysSorted[di-1])] <= lpSum([c4[(c.id,daysSorted[di2-1])] for di2 in compNextGames[di]])
|
|
|
|
for c in conferences6:
|
|
cteams= c.teams.filter(active=True)
|
|
for t2 in cteams:
|
|
# alltms.add(t2.id)
|
|
for d1 in days:
|
|
model2 += home[(t2.id,d1)]+away[(t2.id,d1)] <= c6[(c.id,d1)]
|
|
|
|
if runMode!='Improve':
|
|
for (d1,d2) in day3pairs:
|
|
model2 += c6[(c.id,d1)] == c6[(c.id,d2)]
|
|
else:
|
|
for d1 in day34pairs.keys():
|
|
if len(day34pairs[d1])>0:
|
|
model2 += c6[(c.id,d1)] <= lpSum([c6[(c.id,d2)] for d2 in day34pairs[d1]])
|
|
|
|
for r in rounds:
|
|
model2 += lpSum( [ c6[(c.id,d)] for d in getDays[r] ] ) == 1
|
|
|
|
model2 += lpSum( [ c6[(c.id,d)] for d in days ] ) == 10
|
|
|
|
c5_repeater={}
|
|
for c in conferences5:
|
|
cteams= c.teams.filter(active=True)
|
|
for t2 in cteams:
|
|
# alltms.add(t2.id)
|
|
for d1 in days:
|
|
model2 += home[(t2.id,d1)]+away[(t2.id,d1)] <= c5[(c.id,d1)]
|
|
if runMode!='Improve':
|
|
for (d1,d2) in day3pairs:
|
|
model2 += c5[(c.id,d1)] == c5[(c.id,d2)]
|
|
else:
|
|
for d1 in day34pairs.keys():
|
|
if len(day34pairs[d1])>0:
|
|
model2 += c5[(c.id,d1)] <= lpSum([c5[(c.id,d2)] for d2 in day34pairs[d1]])
|
|
|
|
for r in rounds:
|
|
model2 += lpSum( [ c5[(c.id,d)] for d in getDays[r] ] ) == 1
|
|
|
|
model2 += lpSum( [ c5[(c.id,d)] for d in days ] ) == 10
|
|
|
|
|
|
for t1 in cteams:
|
|
for t2 in cteams:
|
|
if t1.id<t2.id and forbidBackToBack :
|
|
if not t_usePhases[t1.id] and not t_usePhases[t2.id] :
|
|
c5_repeater[(t1.id,t2.id)] = pulp.LpVariable('c5_repeater_'+str(t1.id)+'_'+str(t2.id), lowBound = 0, cat = pulp.LpContinuous)
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for r in [1,2,3,4,5] for d in getRoundDaysByRound[r] ] ) <=1 + c5_repeater [(t1.id,t2.id)]
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for r in [6,7,8,9,10] for d in getRoundDaysByRound[r] ] ) <=1 + c5_repeater [(t1.id,t2.id)]
|
|
|
|
# for rn in [1,2,4,6,7,9]:
|
|
for rn in two_starter_uefa :
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[rn]+getRoundDaysByRound[rn+1] ] ) <=1
|
|
for rn in three_starter_uefa:
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[rn]+getRoundDaysByRound[rn+1]+getRoundDaysByRound[rn+2] ] ) <=1
|
|
|
|
else:
|
|
# for rn in [4]:
|
|
# model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[rn]+getRoundDaysByRound[rn+1]+getRoundDaysByRound[rn+2] ] ) <=1
|
|
for rn in [5]:
|
|
model2 += lpSum( [ x[t1.id,t2.id,d] + x[t2.id,t1.id,d] for d in getRoundDaysByRound[rn]+getRoundDaysByRound[rn+1] ] ) <=1
|
|
|
|
|
|
# if not t1.name in ["Iceland", "Scotland", "Finland", "Faroe Islands"]:
|
|
if not t1.name in ["Iceland", "Faroe Islands"] and False:
|
|
for rn in [3,4,5,6]:
|
|
model2 += break3InRound[(t1.id,rn)]== 0
|
|
# print ("do not " , lpSum( [ homeInRound[(t1.id,r2)]-awayInRound[(t1.id,r2)] for r2 in [rn-2,rn-1,rn] ]) )
|
|
model2 += lpSum( [ homeInRound[(t1.id,r2)]-awayInRound[(t1.id,r2)] for r2 in [rn-2,rn-1,rn] ]) <= 1
|
|
model2 += lpSum( [ homeInRound[(t1.id,r2)]-awayInRound[(t1.id,r2)] for r2 in [rn-2,rn-1,rn] ]) >= -1
|
|
|
|
|
|
# t_in_French_Group={t4 : False for t4 in teams}
|
|
# for c in allConferences:
|
|
# tms = [t.id for t in c.teams.filter(active=True)]
|
|
# print ("C " , tms)
|
|
# franceFound = False
|
|
# for tt in tms:
|
|
# if getTeamById[tt]== "France":
|
|
# franceFound = True
|
|
# if franceFound:
|
|
# for tt in tms:
|
|
# t_in_French_Group[tt]= True
|
|
# print ("found french friend " , tt , getTeamById[tt])
|
|
#
|
|
|
|
|
|
# for t in teams:
|
|
# if not t_usePhases[t] and not t_in_French_Group[t]:
|
|
# model2 += lpSum([c5_repeater[(t1,t2)] for (t1,t2) in c5_repeater.keys() if t in [t1,t2]]) <=1
|
|
|
|
|
|
if len(conferences4)>0 :
|
|
for d1 in days:
|
|
model2 += lpSum( [ c4[(c.id,d1)] for c in conferences4 ] ) >=0
|
|
model2 += lpSum( [ c4[(c.id,d1)] for c in conferences4 ] ) <=5
|
|
|
|
# todo: no 3*5 c4 on days 1,2,6 -> spacing for c3 possible
|
|
# todo: no 3*5 c4 on days 1,5,6 -> spacing for c3 possible
|
|
|
|
# model2 += lpSum( [ c4[(c.id,daysSorted[di-1])] for c in conferences4 for di in [1,2,6]] ) <=14
|
|
# model2 += lpSum( [ c4[(c.id,daysSorted[di-1])] for c in conferences4 for di in [1,5,6]] ) <=14
|
|
# model2 += lpSum( [ c4[(c.id,daysSorted[di-1])] for c in conferences4 for di in [8,9,13]] ) <=14
|
|
# model2 += lpSum( [ c4[(c.id,daysSorted[di-1])] for c in conferences4 for di in [8,12,13]] ) <=14
|
|
# for di in [1,2,3,4,5,6, 8,9,10,11,12,13]:
|
|
# model2 += lpSum( [ c4[(c.id,daysSorted[di-1])] for c in conferences4 ] ) >=3
|
|
|
|
|
|
if runMode!='Improve':
|
|
print ("EXTRA UEFA NL run")
|
|
writeProgress("Running special model ", thisScenario.id,10)
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=0.0, TimeLimit=40,msg=1))
|
|
else:
|
|
model2.solve(XPRESS(msg=1,maxSeconds = 40, options=["THREADS=12"], keepFiles=True))
|
|
|
|
for (c,d) in c4.keys():
|
|
model2 += c4[(c,d)] == c4[(c,d)].value()
|
|
if c4[(c,d)].value() >0.9:
|
|
print ("c4 " , c, getNiceDay[d] )
|
|
|
|
|
|
for (c,d) in c5.keys():
|
|
model2 += c5[(c,d)] == c5[(c,d)].value()
|
|
if c5[(c,d)].value() >0.01:
|
|
print (c, d, c5[(c,d)].value() )
|
|
|
|
|
|
print ("thisSeason.useFeatureBackToBack", thisSeason.useFeatureBackToBack)
|
|
if thisSeason.useFeatureBackToBack:
|
|
print ("critical_day_pairs", critical_day_pairs)
|
|
print ("back2backBlocks", back2backBlocks)
|
|
fiveDayFourRounds=[]
|
|
for d in days:
|
|
fiveDays = [ d2 for d2 in days if getDateTimeDay[d]<= getDateTimeDay[d2] and getDateTimeDay[d2]-getDateTimeDay[d]<=datetime.timedelta(days=4) ]
|
|
fourRounds = []
|
|
for d2 in fiveDays:
|
|
fourRounds+=[ r2 for r2 in getRoundsByDay[d2] ]
|
|
fourRounds=list(set(fourRounds))
|
|
# print (d, fiveDays,fourRounds , len(fourRounds)>=4)
|
|
if len(fourRounds)>=4:
|
|
fiveDayFourRounds.append(fiveDays)
|
|
|
|
bad_travel_in = { t : [] for t in teams}
|
|
bad_travel_out = { t : [] for t in teams}
|
|
for (t1,t2,c) in bad_travels:
|
|
bad_travel_in[t2].append((t1,color_weight[c]))
|
|
bad_travel_out[t1].append((t2,color_weight[c]))
|
|
|
|
for fdfr in fiveDayFourRounds:
|
|
for t in realteams:
|
|
model2 += lpSum([ home[(t,d)] + away[(t,d)] for d in fdfr ]) <= 3 + 0.001*badBackToBack[(t,fdfr[0])]
|
|
# print(t, " cannot play more than three times in ", fdfr)
|
|
|
|
for (d1,d2) in critical_day_pairs:
|
|
# print ("no time zone crossings for at days " , getNiceDay[d1]," -> ",getNiceDay[d2],nextCritical[d2])
|
|
for t in realteams:
|
|
|
|
# print ("counting b2b for ", getTeamById[t])
|
|
model2 += home[(t,d1)]+home[(t,d2)]+away[(t,d1)]+away[(t,d2)] <= 1 + badBackToBack[(t,d1)]
|
|
rd1s=getRoundDaysByDay[d1]
|
|
rd2s=getRoundDaysByDay[d2]
|
|
|
|
if nRounds <= 72 and nextCritical[d2]:
|
|
# print ("no 3 series for " , t , " at days " , d1,d2,nextCritical[d2])
|
|
model2 += lpSum([ home[(t,d)] + away[(t,d)] for d in [d1,d2,nextCritical[d2]] ]) <= 2 + 0.0001*badBackToBack[(t,d1)]
|
|
|
|
for (tms1,tms2,w) in back2backBlocks:
|
|
model2 += lpSum([x[(t1,t,rd1)] for rd1 in rd1s for t1 in tms1 if gameCntr[(t1,t)]>0]) + lpSum([x[(t2,t,rd2)] for rd2 in rd2s for t2 in tms2 if gameCntr[(t2,t)]>0 ]) <= 1 + 0.001/w*badBackToBack[(t,d1)]
|
|
|
|
if currentAwayLocation[(t,d1)] and currentAwayLocation[(t,d2)]:
|
|
t1 = currentAwayLocation[(t,d1)]
|
|
for (t2,w) in bad_travel_out[t1]:
|
|
if t2==currentAwayLocation[(t,d2)]:
|
|
print ("TRAVEL BACK TO BACK FOUND WITH WEIGHT ", w, ":", getNiceDay[d1] ,getTeamById[t] , " -> " , getTeamById[currentAwayLocation[(t,d1)]] , " -> " , getTeamById[currentAwayLocation[(t,d2)]] )
|
|
model2 += lpSum([x[(t1,t,rd1)] for rd1 in rd1s ]) + lpSum([x[(t2,t,rd2)] for rd2 in rd2s ]) <= 1 + 0.001/w*badBackToBack[(t,d1)]
|
|
|
|
# todo : add red teams to distant_teams here to take care that trips do not start and end with bad b2b
|
|
# print ("after home game no away game at " , rd1s, rd2s, "for ", t , " in ", distant_teams[t])
|
|
if not blocked_arena[(t,d1,"----")]:
|
|
model2 += home[(t,d1)] + lpSum([ wg*x[(t2,t,rd2)] for rd2 in rd2s for (t2,wg) in bad_travel_out[t] if gameCntr[(t2,t)]>0 ]) <= 1 + 0.001*badBackToBack[(t,d1)]
|
|
if not blocked_arena[(t,d2,"----")]:
|
|
# if d1==32363 and getTeamById[t]=="Cleveland Cavaliers":
|
|
# print (" ++++ ",getTeamById[t] , rd1s, bad_travel_in[t] )
|
|
# for t33 in bad_travel_in[t]:
|
|
# print("+++++ " ,t33, getTeamById[t33] , gameCntr[(t33,t)])
|
|
# print (" ++++ ",lpSum([ wg*x[(t2,t,rd1)] for rd1 in rd1s for (t2,wg) in bad_travel_in[t] if gameCntr[(t2,t)]>0 ]) )
|
|
model2 += lpSum([ wg*x[(t2,t,rd1)] for rd1 in rd1s for (t2,wg) in bad_travel_in[t] if gameCntr[(t2,t)]>0 ]) + home[(t,d2)] <= 1 + 0.001*badBackToBack[(t,d1)]
|
|
|
|
badBackToBack_Total = lpSum([badBackToBack[(t,d1)] for t in teams for (d1,d2) in critical_day_pairs])
|
|
specialObjectives+= 50*gew['Breaks']* badBackToBack_Total
|
|
# END SPECIAL CONSTRAINTS
|
|
|
|
model2+= standardObjectives +specialObjectives
|
|
|
|
print("Model built now solving .... ")
|
|
|
|
nRuns =1
|
|
maxSolveTime = 300
|
|
|
|
if thisSeason.groupBased:
|
|
maxSolveTime = 40
|
|
|
|
mipgap=0.01
|
|
|
|
# print ("######## Testing")
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=120,msg=1))
|
|
|
|
|
|
use_LP_heuristic= False
|
|
print (runMode=='New' , useBasicGames , runPatternAssignmentFirst)
|
|
|
|
if runMode=='New' and useBasicGames and runPatternAssignmentFirst:
|
|
print ('Coupling Home Away to patterns', use_LP_heuristic)
|
|
|
|
if use_LP_heuristic:
|
|
model2.solve(GUROBI(MIPGap=mipgap, TimeLimit=maxSolveTime,msg=1))
|
|
roundedGames = { (t1,t2,r) : gameInBasicRound[(t1,t2,r)].value() for r in rounds1 for t1 in realteams for t2 in realteams if t1!=t2 }
|
|
|
|
for g in roundedGames:
|
|
if roundedGames[g]>0:
|
|
print (g, " : " ,roundedGames[g])
|
|
|
|
model5 = pulp.LpProblem("League Scheduling Model -- LP heuristic_"+str(thisScenario.id), pulp.LpMinimize)
|
|
x5={(t1,t2,r) : pulp.LpVariable('x4_'+str(t1)+'_'+str(t2)+'_'+str(r), lowBound = 0, upBound = 1, cat = pulp.LpInteger) for (t1,t2,r) in roundedGames.keys() }
|
|
for t1 in realteams:
|
|
for t2 in realteams:
|
|
if t1<t2 :
|
|
model5+= sum( x5[(t1,t2,r)] + x5[(t2,t1,r)] for r in rounds1)== 1
|
|
for r in rounds1:
|
|
model5+= sum( x5[(t1,t2,r)] +x5[(t2,t1,r)] for t2 in realteams if t1!=t2 ) ==1
|
|
|
|
model5 += sum ( -roundedGames[g] * x5[g] for g in roundedGames.keys())
|
|
model5.solve(GUROBI(MIPGap=0.1, TimeLimit=maxSolveTime,msg=1))
|
|
|
|
for (t1,t2,r) in roundedGames.keys() :
|
|
if x5[(t1,t2,r)].value()>0.1:
|
|
print (r, " " , t1," - " , t2, " : " , roundedGames[(t1,t2,r)])
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 1
|
|
gameInBasicRound[(t1,t2,r)].upBound = 1
|
|
gameInBasicRound[(t2,t1,r+nTeams-1)].lowBound = 1
|
|
gameInBasicRound[(t2,t1,r+nTeams-1)].upBound = 1
|
|
|
|
else:
|
|
# use2BreakPatterns
|
|
undecidedGames = gameCntr.copy()
|
|
for t in realteams:
|
|
for r in basicRounds:
|
|
if r > 0 and runPatternAssignmentFirst and False:
|
|
# print ("homeInBasicRound[(",str(t),",",str(r), " ] == " , int(homePat[(t,r)].value()))
|
|
# print ("awayInBasicRound[(",str(t),",",str(r), " ] == " , 1-homePat[(t,r)].value())
|
|
# homeInBasicRound[(t,r)].lowBound = homePat[(t,r)].value()
|
|
homeInBasicRound[(t,r)].upBound = homePat[(t,r)].value()
|
|
# awayInBasicRound[(t,r)].lowBound = 1-homePat[(t,r)].value()
|
|
awayInBasicRound[(t,r)].upBound = awayPat[(t,r)].value()
|
|
|
|
for (t1,t2) in games:
|
|
for r in basicRounds:
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 0
|
|
gameInBasicRound[(t1,t2,r)].upBound = 1
|
|
gameInBasicRound[(t1,t2,r)].upBound = 0
|
|
|
|
cntr =0
|
|
for (t1,t2,r) in chosenGames:
|
|
# print (t1,t2,r)
|
|
homers = [t1] + regionalKids[t1]
|
|
awayers = [t2] + regionalKids[t2]
|
|
# print (" chosen game " ,r, homers , awayers, getRoundDaysByBasicRound[r] , getMaxGameOnRoundDaysByBasicRound[r],defaultGameRepetions)
|
|
# print (" chosen game " , getMaxGameOnRoundDaysByBasicRound[r])
|
|
theseRounds = sorted(list(set([ r2 for (r2,d) in getRoundDaysByBasicRound[r]])))
|
|
if len(theseRounds)>0:
|
|
fr = theseRounds[0]
|
|
lr = theseRounds[-1]
|
|
# print ( " RDS " , theseRounds , theseRounds[0], min([ r2 for (r2,d) in getRoundDaysByBasicRound[r]]) )
|
|
for t11 in homers:
|
|
for t22 in awayers:
|
|
#print (" - chosen game " , getTeamById[t11], getTeamById[t22], getRoundDaysByBasicRound[r] , getMaxGameOnRoundDaysByBasicRound[r])
|
|
# model2 += gameInBasicRound[(t11,t22,r)] >= 1 - 0.9*missingGamesVio[(t11,t22)]
|
|
if (t11,t22,r) in gameInBasicRound.keys():
|
|
gameInBasicRound[(t11,t22,r)].lowBound = defaultGameRepetions-1
|
|
gameInBasicRound[(t11,t22,r)].upBound = defaultGameRepetions
|
|
# print ("setting ",(t11,t22,r) , defaultGameRepetions-1, defaultGameRepetions )
|
|
|
|
if tripStartHeuristicGroupsize>=2 and False:
|
|
model2+= x_round[(t11,t22,fr)] == x_round[(t11,t22,fr+1)]
|
|
model2+= x_round[(t11,t22,fr+2)] == x_round[(t11,t22,fr+3)]
|
|
# print ("setting " , t11,t22, " twice")
|
|
# model2+= x_round[(t1,t2,lr)] == x_round[(t1,t2,lr-1)]
|
|
|
|
# print ( t11,t22, (t11,t22) in undecidedGames, undecidedGames)
|
|
undecidedGames[(t11,t22)]-=defaultGameRepetions
|
|
cntr+=1
|
|
else:
|
|
print ("PROBLEM " , theseRounds, homers, awayers, r)
|
|
print (cntr, " games set")
|
|
# print (len(undecidedGames), " undecided Games :", undecidedGames)
|
|
for (t1,t2) in games:
|
|
# if gameCntr[(t1,t2)]>0:
|
|
# print ("to be scheduled : " , getTeamById[ t1], " --- " , getTeamById[ t2] , gameCntr[(t1,t2)])
|
|
if undecidedGames[(t1,t2)]!=0 and undecidedGames[(t1,t2)]!=-undirectedGameCntr[(t1,t2)]:
|
|
print ("not scheduled yet " , getTeamById[ t1], " --- " , getTeamById[ t2] , undecidedGames[(t1,t2)])
|
|
for r in basicRounds:
|
|
gameInBasicRound[(t1,t2,r)].upBound = defaultGameRepetions
|
|
|
|
for ttr in x.keys():
|
|
makeIntVar(x[ttr])
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 120, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=0.3, TimeLimit=180,msg=1))
|
|
else:
|
|
model2.solve(XPRESS(msg=1,maxSeconds = 120, options=["THREADS=12"], keepFiles=True))
|
|
|
|
for ttr in x.keys():
|
|
if getVal(x[ttr])>0.9:
|
|
# print ( "SETTING GAME ", ttr, getVal(x[ttr]) )
|
|
setLB(x[ttr],1)
|
|
|
|
for (t1,t2) in games:
|
|
for r in basicRounds:
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 0
|
|
gameInBasicRound[(t1,t2,r)].upBound = defaultGameRepetions
|
|
# if gameInBasicRound[(t1,t2,r)].value()>0 and gameInBasicRound[(t1,t2,r)].value()<2 :
|
|
# print ("??",getTeamById[t1],getTeamById[t2],r, gameInBasicRound[(t1,t2,r)].value())
|
|
|
|
|
|
|
|
|
|
# # TEST START
|
|
# for t1 in realteams:
|
|
# for t2 in realteams:
|
|
# if t1!=t2:
|
|
# for r in basicRounds:
|
|
# gameInBasicRound[(t1,t2,r)].lowBound = 0
|
|
# gameInBasicRound[(t1,t2,r)].upBound = 0
|
|
|
|
# cntr =0
|
|
# undecidedGames = [ (t1,t2) for t1 in realteams for t2 in realteams if t1!=t2 ]
|
|
# for (t1,t2,r) in chosenGames:
|
|
# homers = [t1] + regionalKids[t1]
|
|
# awayers = [t2] + regionalKids[t2]
|
|
# for t11 in homers:
|
|
# for t22 in awayers:
|
|
# gameInBasicRound[(t11,t22,r)].lowBound = 1
|
|
# gameInBasicRound[(t11,t22,r)].upBound = 1
|
|
# undecidedGames.remove((t11,t22))
|
|
# cntr+=1
|
|
# print (cntr, " games set")
|
|
# print (len(undecidedGames), " undecided Games :", undecidedGames)
|
|
# for (t1,t2) in undecidedGames:
|
|
# for r in basicRounds:
|
|
# gameInBasicRound[(t1,t2,r)].upBound = 1
|
|
|
|
# for ttr in x.keys():
|
|
# x[ttr].cat= LpInteger
|
|
|
|
# if solver == "CBC":
|
|
# model2.solve(PULP_CBC_CMD(fracGap = 0.0, maxSeconds = 40, threads = 8,msg=1))
|
|
# elif solver == "Gurobi":
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=120,msg=1))
|
|
# else:
|
|
# model2.solve(XPRESS(msg=1,maxSeconds = 25, keepFiles=True))
|
|
|
|
# for ttr in x.keys():
|
|
# if x[ttr].value()>0.01:
|
|
# print ( ttr, x[ttr].value() )
|
|
|
|
|
|
# # TEST END
|
|
|
|
|
|
else:
|
|
nRuns=nPhases
|
|
# maxSolveTime = 120
|
|
mipgap=0.0
|
|
# mipgap=0.95
|
|
|
|
# nRuns =1
|
|
onlyReopt= True
|
|
onlyReopt= False
|
|
onlyFewTrips= False
|
|
singleTripWeight =10
|
|
|
|
if onlyReopt:
|
|
nRuns=0
|
|
|
|
maxIntRound=nRounds
|
|
|
|
print (optSteps)
|
|
|
|
missing_imp=[]
|
|
cntr =0
|
|
for st in optSteps:
|
|
print (" - " ,st )
|
|
cntr +=1
|
|
if runMode=='New' and st[0] == "HARDCONSTRAINTS":
|
|
for bl in blockings:
|
|
blockingVio[bl['id']].upBound=0
|
|
print ("blocking tightened : " , getTeamById [bl['team_id']] , bl['day_id'] )
|
|
for enc in encwishes:
|
|
if enc['reason']=="Seed Game":
|
|
encVio[enc['id']].upBound=0
|
|
|
|
|
|
if runMode=='New' and len(st)>=1 and st[0] in ["PATTERNS","HOMEAWAY", "BASICGAME", "GAME","GAMES", "GROUP", "TRIPS", "LP-HEURISTIC"]:
|
|
newRounds = []
|
|
print()
|
|
optTarget = st[0]
|
|
if len(st)>1 :
|
|
for rf in st[1].split(","):
|
|
rr= rf.split("-")
|
|
if len(rr)==1 :
|
|
newRounds.append(min(nRounds,int(rr[0])))
|
|
else:
|
|
for ii in range (int(rr[0]), min(nRounds, int(rr[1])+1)):
|
|
newRounds.append(ii)
|
|
newRoundsString = st[1]
|
|
else :
|
|
newRounds = rounds
|
|
newRoundsString = "1-"+str(nRounds)
|
|
|
|
optsteptime = maxSolveTime
|
|
optstepgap = mipgap
|
|
|
|
if len(st)>=3 and st[2]!="":
|
|
optstepgap = float(st[2])
|
|
if len(st)>=4 and st[3]!="":
|
|
optsteptime = float(st[3])
|
|
|
|
print (newRounds)
|
|
|
|
# if not thisSeason.minBreaks and runMode=='Improve':
|
|
if st[0] == "LP-HEURISTIC":
|
|
print("STARTING LP HEURISTIC")
|
|
|
|
if st[0] == "PATTERNS":
|
|
for (p,t,ph) in assignPattern2.keys():
|
|
assignPattern2[(p,t,ph)].cat = pulp.LpInteger
|
|
|
|
|
|
if st[0] == "HOMEAWAY":
|
|
for t in teams:
|
|
for r in newRounds:
|
|
homeInRound[(t,r)].cat = pulp.LpInteger
|
|
|
|
if st[0] == "BASICGAME":
|
|
for (t1,t2) in games:
|
|
for r in newRounds:
|
|
gameInBasicRound[(t1,t2,r)].cat = pulp.LpInteger
|
|
|
|
if st[0] in ["GAME","GAMES"]:
|
|
for (t,t2) in games:
|
|
for r in newRounds:
|
|
for rd in getRoundDaysByRound[r]:
|
|
makeIntVar(x[(t,t2,rd)])
|
|
# if thisSeason.gamesPerRound=="one day":
|
|
# makeIntVar(x[(t,t2,getRoundDaysByRound[r][0])])
|
|
# print ("makeintvar " ,t1,t2, getRoundDaysByRound[r][0],getRoundDaysByRound[r])
|
|
# else:
|
|
# for rd in getRoundDaysByRound[r]:
|
|
# makeIntVar(x[(t,t2,rd)])
|
|
|
|
getSingleTripElementsByRound = { r : [] for r in rounds}
|
|
if st[0] in ["TRIP","TRIPS"]:
|
|
singleTripWeight =1000
|
|
# onlyFewTrips= True
|
|
for (t1,d,c) in tripToSingleTripElement.keys():
|
|
getSingleTripElementsByRound[getRoundByDay[d]].append((t1,d,c))
|
|
for r in newRounds:
|
|
for tdc in getSingleTripElementsByRound[r]:
|
|
makeIntVar(tripToSingleTripElement[tdc])
|
|
|
|
if st[0] == "GROUP" and len(st)>=5:
|
|
cfname = st[4].strip()
|
|
if cfname in conf_teams.keys():
|
|
optTarget += " "+ cfname
|
|
print ("checking GROUP", st[4].strip())
|
|
for (t1,t2) in games:
|
|
optstepgap = mipgap
|
|
if t1 in conf_teams[cfname] and t2 in conf_teams[cfname]:
|
|
print ("REOPT GROUP ", cfname , t1,t2)
|
|
for r in newRounds:
|
|
makeIntVar(x_round[(t1,t2,r)])
|
|
for rd in getRoundDaysByRound[r]:
|
|
makeIntVar(x[(t1,t2,rd)])
|
|
|
|
|
|
# optsteptime= 30
|
|
|
|
print ('########################')
|
|
print ('# SOLVING MODEL '+optTarget+' FOR ROUNDS '+ newRoundsString+' USING GAP ' + str(optstepgap) + ' and MAXTIME ' + str(optsteptime) + ' #')
|
|
print ('########################')
|
|
writeProgress("Optimize "+st[0]+" for rounds " + newRoundsString, thisScenario.id, int( cntr/len(optSteps)*100 ))
|
|
|
|
if RUN_ENV == 'celery' and task:
|
|
task.update_state(state='Solving Model '+str(st[0]), meta={'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = optstepgap, maxSeconds = optsteptime, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=optstepgap, TimeLimit=optsteptime,msg=1, Method=2,NodeMethod=2))
|
|
else:
|
|
# for debugging:
|
|
# with open ("model2.txt", "w") as f:
|
|
# f.write(model2.__repr__())
|
|
model2.solve(XPRESS(msg=1,targetGap=optstepgap, maxSeconds = optsteptime, options=["THREADS=12,DETERMINISTIC=0,CUTSTRATEGY=0"], keepFiles=True))
|
|
# model2.solve(XPRESS(msg=1,targetGap=optstepgap, maxSeconds = optsteptime, options=["THREADS=12,DEFAULTALG=4,DETERMINISTIC=0,CUTSTRATEGY=0"], keepFiles=True))
|
|
# # model2.solve(XPRESS())
|
|
# model2.solve(XPRESS(path= "/opt/xpressmp/bin/optimizer",msg=True, keepFiles=True))
|
|
|
|
if model2.status<0:
|
|
print("Status: " , model2.status)
|
|
if solver != "xpress":
|
|
writeProgress("Model infeasible .", thisScenario.id,0)
|
|
if RUN_ENV == 'celery' and task:
|
|
print({'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
else:
|
|
print('Model could not be solved')
|
|
|
|
if not lowerBoundFound:
|
|
lowerBoundFound=value(model2.objective)
|
|
|
|
cntr_rnd =0
|
|
if st[0] == "LP-HEURISTIC":
|
|
for (t1,t2) in games:
|
|
for r in newRounds:
|
|
for rd in getRoundDaysByRound[r]:
|
|
if getVal(x[(t1,t2,rd)])>0.65:
|
|
setLB(x[(t1,t2,rd)],1)
|
|
print ("rounding up " , getTeamById[t1], "-" ,getTeamById[t2], rd , getVal(x[(t1,t2,rd)]))
|
|
cntr_rnd +=1
|
|
# print (t1,t2,rd)
|
|
# else:
|
|
# setUB(x[(t1,t2,rd)],0)
|
|
# # print(t1,t2 , " no game ")
|
|
# # x[(t1,t2,rd)].upBound = 0
|
|
print ("Totally rounded up " , cntr_rnd)
|
|
|
|
|
|
if st[0] == "PATTERNS":
|
|
for (p,t,ph) in assignPattern2.keys():
|
|
if assignPattern2[(p,t,ph)].value() >0.9 :
|
|
print ('fixing pattern '+ str(p) + ' : '+ getTeamById[t] +" in phase " + str(ph))
|
|
assignPattern2[(p,t,ph)].lowBound = 1
|
|
else:
|
|
assignPattern2[(p,t,ph)].upBound = 0
|
|
|
|
|
|
if st[0] == "HOMEAWAY":
|
|
print (teams)
|
|
print (newRounds)
|
|
for t in teams:
|
|
for r in newRounds:
|
|
if homeInRound[(t,r)].value() >0.9 :
|
|
print ('fixing home '+ str(r) + ' : '+ getTeamById[t] +" " + str(homeInRound[(t,r)].value()))
|
|
homeInRound[(t,r)].lowBound = 1
|
|
else:
|
|
homeInRound[(t,r)].upBound = 0
|
|
|
|
|
|
if st[0] == "BASICGAME":
|
|
for r in newRounds:
|
|
for (t1,t2) in games:
|
|
if getTeamById[t1]!="-" and getTeamById[t2]!="-" and (t1,t2,r) in gameInBasicRound.keys() and type(gameInBasicRound[(t1,t2,r)])!= int:
|
|
if getVal(gameInBasicRound[(t1,t2,r)])>0.9:
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 1
|
|
else:
|
|
gameInBasicRound[(t1,t2,r)].upBound = 0
|
|
# print (r, ' : ', getTeamById[t1], ' - ',getTeamById[t2] )
|
|
|
|
if st[0] in ["GAME","GAMES"]:
|
|
# crappyGames = [ g for g in fixedGames if fixedGameVio[g].value() >0.9 ]
|
|
feedback = "Optimize games...."
|
|
missing_imp=[]
|
|
for (t1,t2,d) in fixedGames:
|
|
if fixedGameVio[(t1,t2,d)].value() >0.9:
|
|
feedback += 'Not fixed :' +getDayById[d]['day'] +' : '+getTeamById[t1] + ' - ' + getTeamById[t2] + '<br> '
|
|
for (t1,t2,d) in fixedGames2:
|
|
if fixedGame2Vio[(t1,t2,d)].value() >0.9:
|
|
feedback += 'Not fixed :' +getDayById[d]['day'] +' : '+getTeamById[t1] + ' - ' + getTeamById[t2] + '<br> '
|
|
for (t1,t2) in realgames:
|
|
if missingGamesVio[(t1,t2)].value() >0.9:
|
|
feedback += 'Game missing : '+getTeamById[t1] + ' - ' + getTeamById[t2] + ' ' + str(missingGamesVio[(t1,t2)].value()) + '<br> \n'
|
|
missing_imp += [(1,nRounds,[t1,t2], 50)]
|
|
|
|
print (missing_imp)
|
|
print (feedback)
|
|
print ("number of assigned games : " , sum([getVal(x[ttrd]) for ttrd in x.keys()]))
|
|
|
|
for (t1,t2) in games:
|
|
for r in newRounds:
|
|
for rd in getRoundDaysByRound[r]:
|
|
if getVal(x[(t1,t2,rd)])>0.9:
|
|
setLB(x[(t1,t2,rd)],1)
|
|
print ("fixing " ,t1,t2,rd, x[(t1,t2,rd)].lowBound )
|
|
else:
|
|
setUB(x[(t1,t2,rd)],0)
|
|
# print(t1,t2 , " no game ")
|
|
# x[(t1,t2,rd)].upBound = 0
|
|
|
|
# for (t1,t2,rd) in x.keys():
|
|
# if getVal(x[(t1,t2,rd)])>0.9:
|
|
# print ("setLB(x[",t1,",",t2, "," , rd , "],1)")
|
|
|
|
if st[0] in ["TRIP","TRIPS"]:
|
|
for r in newRounds:
|
|
for tdc in getSingleTripElementsByRound[r]:
|
|
if getVal(tripToSingleTripElement[tdc])>0.9:
|
|
setLB(tripToSingleTripElement[tdc],1)
|
|
print ("fixing " ,tdc, tripToSingleTripElement[tdc] )
|
|
else:
|
|
setUB(tripToSingleTripElement[tdc],0)
|
|
|
|
if st[0] == "GROUP" and len(st)>=5:
|
|
print ("fixing GROUP", st[4].strip())
|
|
for (t1,t2) in games:
|
|
if t_conference[t1]!=0 and t_conference[t2]!=0 and st[4].strip() in [ t_conference[t2].name, t_conference[t1].name] :
|
|
print ("checking in group ", t1,t2)
|
|
for r in newRounds:
|
|
for rd in getRoundDaysByRound[r]:
|
|
if getVal(x[(t1,t2,rd)])>0.99:
|
|
# if x[(t1,t2,rd)].value()>0.99:
|
|
setLB(x[(t1,t2,rd)],1)
|
|
print ("fixing in GROUP",t1,t2,rd)
|
|
# print (t1,t2,rd)
|
|
else:
|
|
setUB(x[(t1,t2,rd)],0)
|
|
|
|
for r in basicRounds:
|
|
for t1 in realteams:
|
|
homeInBasicRound[(t1,r)].lowBound = 0
|
|
homeInBasicRound[(t1,r)].upBound = 10
|
|
awayInBasicRound[(t1,r)].lowBound = 0
|
|
awayInBasicRound[(t1,r)].upBound = 10
|
|
for t2 in opponents[t1]:
|
|
if (t1,t2) in games:
|
|
gameInBasicRound[(t1,t2,r)].cat = pulp.LpContinuous
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 0
|
|
|
|
debug = False
|
|
if debug:
|
|
print (str(blockingVioTotal.value()) , " violated Blockings out of " , nBlockingHome )
|
|
for bl in blockings :
|
|
if (blockingVio[bl['id']].value()>0.9) and bl['type'] in ["Home", "Hide"] :
|
|
print (bl )
|
|
|
|
print (str(travelVioTotal.value()) , " violated Travel Restrictions out of " , nBlockingAway )
|
|
for bl in blockings :
|
|
if (blockingVio[bl['id']].value()>0.9) and bl['type']=='Away' :
|
|
print (bl )
|
|
|
|
if gew['Breaks'] > 0:
|
|
print (str(breakVioTotal.value()) , " Breaks :" )
|
|
for bl in breaks :
|
|
for t in realteams:
|
|
if (breakVio[(bl['id'],t)].value()>0.9) :
|
|
print (bl, ' ' , str(t) )
|
|
|
|
if gew['Home-/Away'] > 0:
|
|
print ("Violated HA-Wishes out of " , len(hawishes) )
|
|
for haw in hawishes :
|
|
for el in elemHaWishes[haw['id']]:
|
|
if (HawVioTooLess[el].value()+HawVioTooMuch[el].value() >0.9) :
|
|
print (haw)
|
|
|
|
if gew['Encounters'] > 0:
|
|
print ("Violated Encounter-Wishes out of " , nElemEncWishes )
|
|
for enc in encwishes :
|
|
if (encVio[enc['id']].value()>0.9) :
|
|
print (enc)
|
|
|
|
|
|
for t in realteams:
|
|
for r in newRounds:
|
|
homeInRound[(t,r)].cat = pulp.LpContinuous
|
|
for t2 in opponents[t]:
|
|
for rd in getRoundDaysByRound[r]:
|
|
# if x[(t,t2,d)].value() >0.1 :
|
|
# print ('looking '+ str(r) + ' : '+ getTeamById[t] + ' - '+ getTeamById[t2] + " " + str(x[(t,t2,d)].value()))
|
|
if (t,t2) in games and getVal(x[(t,t2,rd)]) >0.9 :
|
|
# print ('fixing '+ str(rd) + ' : '+ getTeamById[t] + ' - '+ getTeamById[t2] )
|
|
setLB(x[(t,t2,rd)], x[(t,t2,rd)].value())
|
|
currentSolution =[ (t1,t2,r,d) for (t1,t2) in realgames for (r,d) in roundDays if getVal(x[(t1,t2,(r,d))]) >0.9 ]
|
|
|
|
# print ("####################")
|
|
# print ("testing feasibility 2")
|
|
# print ("####################")
|
|
# model2.solve(XPRESS(msg=1,maxSeconds = 10 , keepFiles=True))
|
|
# print ("####################")
|
|
# print ("testing done")
|
|
# print ("####################")
|
|
|
|
print (impScript)
|
|
|
|
for r in rounds:
|
|
for t in teams:
|
|
homeInRound[(t,r)].lowBound = 0
|
|
homeInRound[(t,r)].upBound = 1
|
|
|
|
for (t1,t2) in games:
|
|
for r in rounds:
|
|
for rd in getRoundDaysByRound[r]:
|
|
makeIntVar(x[(t1,t2,rd)])
|
|
|
|
if runMode!='Improve':
|
|
if mathModelName=="NBA":
|
|
print ("buidling badRepeaters")
|
|
badRepeaters = [ (t,r) for (t,r) in badRepeater.keys() if badRepeater[(t,r)].value()>0.9]
|
|
for (t,r) in badRepeaters :
|
|
print ("bad repeater :",r, getTeamById[t])
|
|
|
|
if thisSeason.useFeatureBackToBack:
|
|
print ("buidling badBackToBackers")
|
|
badBackToBackers = [ (t,r) for (t,r) in badBackToBack.keys() if badBackToBack[(t,r)].value()>0.9]
|
|
print ("done buidling badBackToBackers")
|
|
for (t,r) in badBackToBackers :
|
|
print ("bad back to back :", int(badBackToBack[(t,r)].value()) , getNiceDay[r], getTeamById[t] )
|
|
|
|
tightenBlockings = nTeams>20 and nRounds>60
|
|
if runMode=='Improve':
|
|
if tightenBlockings:
|
|
for bl in blockings:
|
|
if blockingVio[bl['id']].value()==0:
|
|
blockingVio[bl['id']].upBound=0
|
|
print ("blocking tightened : " , bl['team'] , bl['day'] )
|
|
|
|
print ('Solved Again')
|
|
print ('NOW REOPT')
|
|
|
|
mipgap=0.05
|
|
|
|
|
|
starweights= sorted([ starweight[t] for t in teams], reverse = True)
|
|
|
|
localsearch_time = max(0,min(localsearch_time, 0.9*TASK_TIME_LIMIT-(time.time()-start_time)))
|
|
|
|
if runMode == 'New' and localsearch_time == 0:
|
|
localsearch = False
|
|
else:
|
|
localsearch = True
|
|
|
|
# localsearch_time=10
|
|
|
|
print (starweights)
|
|
|
|
nFarTeams = 1
|
|
if gew['Trips'] > 5:
|
|
# nFarTeams += gew['Trips'] -5
|
|
nFarTeams = nTeams
|
|
|
|
nFarTeams = min(nFarTeams,len(starweights)-1)
|
|
|
|
print ("nFarTeams ", nFarTeams)
|
|
print (starweight)
|
|
|
|
farTeams = [ t for t in teams if starweight[t] > starweights[nFarTeams] ]
|
|
print ("farTeams ", farTeams)
|
|
|
|
# cntr=0
|
|
# for (t,t1,t2,r) in tripSaving.keys():
|
|
# if t in farTeams or t1 in farTeams or t2 in farTeams :
|
|
# # print ("consider trip " , (t,t1,t2,r) )
|
|
# cntr+=4
|
|
# tripSaving[(t,t1,t2,r)].upBound =1
|
|
# model2 += tripSaving[(t,t1,t2,r)] <= sum([ (x[(t1,t,(r,d) )]+x[(t2,t,(r,d))]) for d in [ latestDay[r] ] ])
|
|
# model2 += tripSaving[(t,t1,t2,r)] <= sum([ (x[(t1,t,(r+1,d))]+x[(t2,t,(r+1,d))]) for d in [earliestDay[r+1]] ])
|
|
# model2 += tripSaving[(t,t1,t2,r)] <= sum([ (x[(t1,t,(r,latestDay[r]))]+x[(t1,t,(r+1,earliestDay[r+1]))]) ])
|
|
# model2 += tripSaving[(t,t1,t2,r)] <= sum([ (x[(t2,t,(r,latestDay[r]))]+x[(t2,t,(r+1,earliestDay[r+1]))]) ])
|
|
# print (str(cntr) + ' constraints added' )
|
|
|
|
local_start =time.time()
|
|
|
|
last_objective =value(model2.objective)
|
|
|
|
forbidRepetitions=True
|
|
forbidRepetitions=False
|
|
|
|
useDailyTrips = nRounds*nTeams <=200
|
|
|
|
print ("useDailyTrips" ,useDailyTrips , nRounds , nTeams )
|
|
|
|
if localsearch:
|
|
cntr =0
|
|
|
|
if thisSeason.tripMode=="Clusters":
|
|
|
|
if useDailyTrips:
|
|
for d1 in days:
|
|
otherTripDays = [ d2 for d2 in days if getDateTimeDay[d1]< getDateTimeDay[d2] and getDateTimeDay[d2]<=getDateTimeDay[d1]+datetime.timedelta(days=thisSeason.maxDistanceWithinTrip+1) and (len(getRoundsByDay[d1])*len(getRoundsByDay[d2])>1 or list(getRoundsByDay[d1])!=list(getRoundsByDay[d2]) )]
|
|
|
|
for t in realteams:
|
|
for c in clusters:
|
|
if gew['Trips']>0 and not c in t_clusters[t] and len(otherTripDays)>0:
|
|
tripToClusterDaily[(t,d1,c)].upBound=1
|
|
# tripToClusterDaily[(t,d1,c)] = pulp.LpVariable('tripToClusterDaily_'+str(t)+'_'+str(d1)+'_'+str(c), lowBound = 0, upBound = 1, cat = pulp.LpContinuous)
|
|
model2 += tripToClusterDaily[(t,d1,c)] <= away_in_cluster_day[t,d1,c]
|
|
model2 += tripToClusterDaily[(t,d1,c)] <= lpSum([away_in_cluster_day[t,d2,c] for d2 in otherTripDays ])
|
|
# print ('considering trip of ' , getTeamById[t], ' in days ' , getNiceDay[d1] , getNiceDay[otherTripDays[0]] , otherTripDays,' to cluster ' , c , cluster_teams[c])
|
|
cntr +=2
|
|
else :
|
|
for r in rounds:
|
|
otherTripRounds = [r2 for r2 in rounds if r2>r and getDateTimeDay[latestDay[r]]<= getDateTimeDay[earliestDay[r2]] and getDateTimeDay[earliestDay[r2]]-getDateTimeDay[latestDay[r]]<=datetime.timedelta(days=thisSeason.maxDistanceWithinTrip+1)]
|
|
# print ("trip rounds ", r, otherTripRounds)
|
|
for t in realteams:
|
|
# forbid same opponents on successice days
|
|
for t2 in realteams:
|
|
if t!=t2 and r>1 and forbidRepetitions:
|
|
model2 += sum([ (x[(t,t2,rd )]+x[(t2,t,rd)]) for rd in getRoundDaysByRound[r-1]+getRoundDaysByRound[r] ]) <= 1
|
|
|
|
for c in clusters:
|
|
if len(otherTripRounds)>0 and gew['Trips']>0 and not c in t_clusters[t] :
|
|
tripToCluster[(t,r,c)].upBound=1
|
|
model2 += tripToCluster[(t,r,c)] <= away_in_cluster[t,r,c]
|
|
model2 += tripToCluster[(t,r,c)] <= lpSum([away_in_cluster[t,r2,c] for r2 in otherTripRounds ])
|
|
# print ('considering trip of ' , getTeamById[t], ' in rounds ' , r , otherTripRounds,' to cluster ' , c )
|
|
cntr +=2
|
|
|
|
# else :
|
|
# model2 += tripToCluster[(t,r,c)] == 0
|
|
else:
|
|
tripDayPairs = {}
|
|
for d1 in days:
|
|
for d2 in days:
|
|
daysBetween = (getDateTimeDay[d2]-getDateTimeDay[d1]).days -1
|
|
if daysBetween>=0 and getDayMaxGames[d1]>0 and getDayMaxGames[d2]>0 and daysBetween<=thisSeason.maxDistanceWithinTrip and getRoundByDay[d1]!=getRoundByDay[d2]:
|
|
# print (d1,d2,daysBetween, getNiceDay[d1], getNiceDay[d2], )
|
|
if d1 not in tripDayPairs.keys():
|
|
tripDayPairs[d1]=[]
|
|
tripDayPairs[d1].append((d2, daysBetween))
|
|
|
|
|
|
for t in teams:
|
|
# print (getTeamById[t])
|
|
# print (getTeamById[t],tripElements)
|
|
for (c,v1,v2,v3,v4) in tripElements[t]:
|
|
# if getTeamById[t]=="Regatas":
|
|
# print ("POSS TRIP ",getTeamById[t], (c, [ getTeamById[t3] for t3 in v1 ] , v2, [ getTeamById[t3] for t3 in v2 ] , [ getTeamById[t3] for t3 in v3 ] , [ getTeamById[t3] for t3 in v4 ]), trip_minDays[c], trip_maxDays[c])
|
|
for d1 in tripDayPairs.keys():
|
|
if not onlyFewTrips or t%6==d%6 :
|
|
otherTripDays = [d2 for (d2,daysBetween) in tripDayPairs[d1] if daysBetween>=trip_minDays[c] and daysBetween<=trip_maxDays[c]]
|
|
inBetweenDays = [d2 for (d2,daysBetween) in tripDayPairs[d1] if daysBetween<=trip_minDays[c] ]
|
|
otherTripDays3 = list(set([d2 for d11 in tripDayPairs.keys() for (d2,daysBetween) in tripDayPairs[d11] if d11 in otherTripDays and daysBetween>=trip_minDays[c] and daysBetween<=trip_maxDays[c]]))
|
|
otherTripDays4 = list(set([d2 for d11 in tripDayPairs.keys() for (d2,daysBetween) in tripDayPairs[d11] if d11 in otherTripDays3 and daysBetween>=trip_minDays[c] and daysBetween<=trip_maxDays[c]]))
|
|
# print ("possible? ", getTeamById[t] , getNiceDay[d1], otherTripDays,otherTripDays3,otherTripDays4)
|
|
if len(otherTripDays)>0 and (thisSeason.tripLength <3 or len (v3)==0 or len(otherTripDays3)>0) and (thisSeason.tripLength <4 or len (v4)==0 or len(otherTripDays4)>0) :
|
|
# print ("building trip for " , getTeamById[t], " starting" , getNiceDay[d1] , [ getNiceDay[d] for d in otherTripDays ], [ getNiceDay[d] for d in otherTripDays3 ] , [ getNiceDay[d] for d in otherTripDays4 ] )
|
|
tripToSingleTripElement[(t,d1,c)].upBound=1
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= lpSum([ x[(t2,t,rd)] for t2 in v1 for rd in getRoundDaysByDay[d1]])
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= lpSum([ x[(t2,t,rd)] for t2 in v2 for d2 in otherTripDays for rd in getRoundDaysByDay[d2]])
|
|
for d3 in inBetweenDays:
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= 1- home[t,d3]
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= 1-lpSum([ x[(t2,t,rd)] for t2 in realteams if t2 not in v2 for rd in getRoundDaysByDay[d3]])
|
|
# if getTeamById[t]=="Regatas":
|
|
# print (" ", getNiceDay[d1], [ getNiceDay[d2] for d2 in inBetweenDays ] ,[ getNiceDay[d2] for d2 in otherTripDays ] ," <= ", [ (t2,t,rd) for t2 in v2 for d2 in otherTripDays for rd in getRoundDaysByDay[d2]])
|
|
if thisSeason.tripLength >=3 and len(v3)>0:
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= lpSum([ x[(t2,t,rd)] for t2 in v3 for d2 in set(otherTripDays3) for rd in getRoundDaysByDay[d2]])
|
|
if thisSeason.tripLength >=4 and len(v4)>0:
|
|
model2 += tripToSingleTripElement[(t,d1,c)] <= lpSum([ x[(t2,t,rd)] for t2 in v4 for d2 in set(otherTripDays4) for rd in getRoundDaysByDay[d2]])
|
|
if (len(v3)>0 and len(otherTripDays3)==0) or (len(v4)>0 and len(otherTripDays4)==0) :
|
|
tripToSingleTripElement[(t,d1,c)].upBound=0
|
|
else:
|
|
cntr +=2
|
|
|
|
print ("built ", cntr , " trip constraints")
|
|
|
|
for t1 in realteams:
|
|
for r in rounds:
|
|
homeInRound[(t1,r)].lowBound = 0
|
|
homeInRound[(t1,r)].upBound = 1
|
|
awayInRound[(t1,r)].lowBound = 0
|
|
awayInRound[(t1,r)].upBound = 1
|
|
for rd in roundDays:
|
|
for t2 in opponents[t1]:
|
|
setLB(x[(t1,t2,rd)],0)
|
|
|
|
for (t1,t2) in games:
|
|
for r in rounds:
|
|
if (t1,t2,r) in gameInBasicRound.keys():
|
|
gameInBasicRound[(t1,t2,r)].lowBound = 0
|
|
gameInBasicRound[(t1,t2,r)].upBound = 10
|
|
for rd in getRoundDaysByRound[r]:
|
|
setLB(x[(t1,t2,rd)],0)
|
|
setUB(x[(t1,t2,rd)],1)
|
|
|
|
mipgap=0.00
|
|
if thisSeason.useFeatureTrips and thisLeague.name not in ["EuroLeague Basketball", "La Liga Argentina"] :
|
|
mipgap=0.02
|
|
|
|
maxSolveTime= 2000
|
|
nReopt=4
|
|
nReopt=1*nTeams+5
|
|
for (t1,t2) in games:
|
|
for rd in roundDays:
|
|
setLB(x[(t1,t2,rd)],0)
|
|
|
|
# restore solution just created
|
|
print ("RESTORING OLD SOLUTION !!!")
|
|
if runMode=='New' :
|
|
use_currentSolution= True
|
|
|
|
# print ("TESTING")
|
|
# model2+= lpSum([ fixedGameVio[(t1,t2,d)] for (t1,t2,d) in fixedGames])
|
|
# model2+= standardObjectives
|
|
# for ttr in x.keys():
|
|
# makeIntVar(x[ttr])
|
|
# model2.solve(GUROBI(MIPGap=0.0, TimeLimit=40,msg=1))
|
|
# for (t1,t2,d) in fixedGames:
|
|
# if fixedGameVio[(t1,t2,d)].value() >0.1:
|
|
# print ("Games missing : " , getTeamById[t1] , getTeamById[t2] , getNiceDay[d])
|
|
# print ("TESTING DONE9")
|
|
|
|
|
|
# print ("\n###############\nTIME TAKEN SO FAR : " , time.time()-start_time, "\n##################\n")
|
|
|
|
|
|
newRounds = []
|
|
localSearchResults = []
|
|
while localsearch and len(impScript)>0:
|
|
print ( (time.time() - local_start) , " " , localsearch_time, " ", (time.time() - local_start) < localsearch_time)
|
|
for (impType, firstNewRound,lastNewRound, newTeams, maxTime, par) in impScript:
|
|
if localsearch:
|
|
# if impType != "LOCALAI":
|
|
# print ("trying ")
|
|
# if len(newRounds) == 0:
|
|
# print(lastNewRound)
|
|
# newRounds = range (firstNewRound,lastNewRound+1)
|
|
if impType == "INIT":
|
|
impScript = impScript[1:]
|
|
elif impType in ["SMART_TEAMS", "SMART_ROUNDS"]:
|
|
newTeams, newRounds = smartNeighbor(impType, int(newTeams), int(lastNewRound), model2, x, hawishes, elemHaWishes, HawVioTooLess, HawVioTooMuch,
|
|
elemHaWishTeams,elemHaWishDays, encwishes, elemEncWishes, encVioTooLess,
|
|
encVioTooMuch, prioVal, elemEncWishGames,elemEncWishDays,breaks,realteams,
|
|
breakVio,nRounds,currentSolution,getTeamById)
|
|
if len(newRounds) == 0:
|
|
newRounds = range (firstNewRound,nRounds+1)
|
|
else:
|
|
newRounds = range (firstNewRound,lastNewRound+1)
|
|
|
|
|
|
stadium_sharers = []
|
|
for t3 in newTeams:
|
|
if t_stadium[t3]!='':
|
|
stadium_sharers+=teamsOfStadium[stadium_id[t_stadium[t3]]]
|
|
|
|
print ("newTeams ", newTeams)
|
|
print ("newTeams++ ",stadium_sharers)
|
|
if len(stadium_sharers)<=3:
|
|
newTeams = list(set(newTeams+stadium_sharers))
|
|
print ("allTeams ", newTeams)
|
|
print (newRounds, newTeams, maxTime)
|
|
print ((time.time() - local_start) > localsearch_time)
|
|
print ("STOPCOMPUTATION",Scenario.objects.get(id=thisScenario.id).stopComputation)
|
|
# if time is up then do a last run sticking to currentSolution
|
|
if (time.time() - local_start) > localsearch_time or Scenario.objects.get(id=thisScenario.id).stopComputation:
|
|
print ("Time is up, restoring best solution found so far\n\n")
|
|
localsearch=False
|
|
# firstNewRound=1
|
|
# lastNewRound=nRounds,
|
|
newTeams=[]
|
|
newRounds=[]
|
|
maxTime=2000
|
|
newDays=[]
|
|
for r in newRounds:
|
|
for r2 in rounds :
|
|
if r==r2 or (thisSeason.symmetry and (r2-r)%(nTeams-1)==0 ):
|
|
# print ("adding round " , r2)
|
|
newDays+=getDays[r2]
|
|
|
|
# print (newDays)
|
|
print ("###################################################")
|
|
print ("REOPT {} ROUNDS {} FOR TEAMS {} IN AT MOST {}s".format(impType,newRounds,[getTeamById[t] for t in newTeams],maxTime))
|
|
print ("###################################################")
|
|
print ( " seconds ", (time.time() - local_start))
|
|
if localsearch_time >0 :
|
|
pro=min(95,10+ int(90*((time.time() - local_start) )/ localsearch_time ) )
|
|
print ("§§§§§§§§" ,pro, ' ', (time.time() - local_start) , ' / ', localsearch_time )
|
|
else:
|
|
pro = 95
|
|
ntstring =''
|
|
for t in newTeams:
|
|
ntstring += getTeamById[t] + ', '
|
|
lo = ""
|
|
if isinstance(last_objective,(int,float)):
|
|
lo= " (" + str(int(0.01+last_objective-1)) +")"
|
|
# print (task.request)
|
|
# writeProgress("Reoptimize " +str(firstNewRound)+ " - " + str(lastNewRound ) + " for teams " + ntstring[:-2] + lo, thisScenario.id ,pro)
|
|
if user_is_staff:
|
|
writeProgress("Reoptimize " +str(newRounds) + " for teams " + ntstring[:-2] + lo, thisScenario.id ,pro)
|
|
else:
|
|
writeProgress("Reoptimizing ... " + lo, thisScenario.id ,pro)
|
|
|
|
print ("len(currentSolution) " ,len(currentSolution), use_currentSolution)
|
|
|
|
for (t1,t2,r,d) in currentSolution:
|
|
if (t1,t2,(r,d)) in x.keys():
|
|
if ((t1 in newTeams or t2 in newTeams) and d in newDays) or not use_currentSolution:
|
|
setLB(x[(t1,t2,(r,d))],0)
|
|
setStart(x[(t1,t2,(r,d))],1)
|
|
if par=="STICKY_HOME" and random.random()<1.0:
|
|
model2+= home[(t1,d)]>=1
|
|
# setLB(home[(t1,d)],1)
|
|
print ( getTeamById[t1] , " stays home on " , getNiceDay[d])
|
|
# print (type(home[(t1,d)]))
|
|
|
|
# print ("RELEASING ", (t1,t2,d))
|
|
else:
|
|
setLB(x[(t1,t2,(r,d))],1)
|
|
# print ("FIXXING ", (t1,t2,d))
|
|
|
|
# if RUN_ENV == 'celery' and task:
|
|
# task.update_state(state='PHASE-8', meta={'timestamp':time.time(),'objective':99999999})
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = mipgap, maxSeconds = maxTime, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
model2.solve(GUROBI(MIPGap=mipgap, TimeLimit=maxTime))
|
|
else:
|
|
try:
|
|
model2.solve(XPRESS(msg=1,targetGap=mipgap,maxSeconds = -maxTime, options=["THREADS=12,DEFAULTALG=4,DETERMINISTIC=0,CUTSTRATEGY=0"], keepFiles=True))
|
|
except:
|
|
model2.status = pulp.LpStatusNotSolved
|
|
|
|
# print ("RRRR")
|
|
# for (t1,t2,r) in x_round.keys():
|
|
# if getVal(x_round[(t1,t2,r)])>0.1:
|
|
# print (t1,t2, getTeamById[t1], getTeamById[t2], r, getVal(x_round[(t1,t2,r)]))
|
|
|
|
if model2.status<0 or not value(model2.objective):
|
|
if localsearch:
|
|
continue
|
|
elif solver != "xpress" or not value(model2.objective):
|
|
writeProgress("Model could not be solved within " + str(maxTime)+" seconds ....", thisScenario.id,0)
|
|
if RUN_ENV == 'celery' and task:
|
|
print({'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
else:
|
|
print('Model could not be solved')
|
|
|
|
if RUN_ENV == 'celery' and task:
|
|
# reset_stdout(f,filename)
|
|
task.update_state(state='Reopt Rounds', meta={'timestamp':time.time(),'objective':value(model2.objective), "user ": user_name, "league ": str(thisLeague)})
|
|
|
|
new_currentSolution =[ (t1,t2,r,d) for (t1,t2) in realgames for (r,d) in roundDays if t1!=t2 and getVal(x[(t1,t2,(r,d))]) >0.9999 ]
|
|
|
|
print ("status", model2.status, LpStatus[model2.status], len(new_currentSolution), len(currentSolution), len(new_currentSolution)>=len(currentSolution), not value(model2.objective), value(model2.objective), last_objective)
|
|
|
|
newLSR = LocalSearchResult(season=thisSeason,
|
|
created_at=datetime.datetime.now(),
|
|
searchType=impType,
|
|
nTeams=len(newTeams),
|
|
nRounds=len(newRounds),
|
|
maxTime=maxTime,
|
|
objective=value(model2.objective),
|
|
lastObjective=last_objective or 0,
|
|
nElemEncWishes=nElemEncWishes,
|
|
nElemHaWishes=nElemHaWishes,
|
|
nBlockings=(nBlockingHome+nBlockingAway),
|
|
nGames=nGames,
|
|
nCols=model2.numVariables(),
|
|
nRows=model2.numConstraints(),
|
|
runtime=model2.solutionTime)
|
|
if (specialGameControl or len(new_currentSolution)>=len(currentSolution)) and (solver != "xpress" or model2.status>=0) and ( not last_objective or value(model2.objective) <= last_objective+0.01):
|
|
print ("now using this solution with objective value " + str(value(model2.objective)) )
|
|
for (t1,t2,r,d) in currentSolution:
|
|
if (t1 in newTeams or t2 in newTeams) and d in newDays:
|
|
x[(t1,t2,(r,d))].start=0
|
|
currentSolution =[ (t1,t2,r,d) for (t1,t2) in games for (r,d) in roundDays if t1!=t2 and getVal(x[(t1,t2,(r,d))]) >0.9 ]
|
|
currentSolution =[ (t1,t2,r,d) for (t1,t2,r,d) in currentSolution if getTeamById[t1]!="-" and getTeamById[t2]!="-" ]
|
|
currentLocation = { (t,d) : False for t in teams for d in days}
|
|
for (t1,t2,r,d) in currentSolution:
|
|
currentLocation[(t2,d)]=t1
|
|
currentLocation[(t1,d)]=t1
|
|
|
|
print ("length of current solution " , len (currentSolution))
|
|
last_objective=value(model2.objective)
|
|
print ("Home-/Away : " , gew['Home-/Away'], "*",HawVioTotal.value())
|
|
print ("Pairings :" , gew['Pairings'], "*", pairingVioTotal.value())
|
|
print ("Blockings :" , gew['Blockings'], "*", blockingVioTotal.value() ,"+ " , blockingVioTotal2.value() )
|
|
print ("travelVioTotal :" , gew['Traveling'], "*", travelVioTotal.value())
|
|
print ("gamesTooCloseTotal :" , gew['Blockings'], "*", gamesTooCloseTotal.value())
|
|
print ("tripSavedTotal2 : -5*" , gew['Trips'], "*", tripSavedTotal2.value())
|
|
print ("breakVioTotal :" , gew['Breaks'], "*", breakVioTotal.value())
|
|
print ("break3VioTotal :" , gew['Breaks'], "*", break3VioTotal.value())
|
|
print ("encVioTotal : 5*" , gew['Encounters'], "*", encVioTotal.value())
|
|
print ("seedVioTotal : 5* " , gew['Encounters'], "*", seedVioTotal.value())
|
|
print ("confVioTotal :" , gew['Conferences'], "*", confVioTotal.value())
|
|
print ("tooManyHomesInStadiumTotal :" , gew['Blockings'], "*", tooManyHomesInStadiumTotal.value())
|
|
print ("broadVioTotal :" , gew['Broadcasting'], "*", broadVioTotal.value())
|
|
print ("derbiesMissingTotal :" , gew['Derbies'], "*", derbiesMissingTotal.value())
|
|
print ("competitionVioTotal : 5 *", competitionVioTotal.value())
|
|
print ("tooManyTop4InRowTotal : 0.0 *", tooManyTop4InRowTotal.value())
|
|
print ("fixedGameVioTotal :" , gew['Blockings'], "*", fixedGameVioTotal.value())
|
|
print ("missingGamesVioTotal :" , gew['Blockings'], "*", missingGamesVioTotal.value())
|
|
print ("totalAttendance : -0.01*", totalAttendance.value())
|
|
print ("specialObjectives :" , specialObjectives.value() if specialObjectives else 0)
|
|
if thisSeason.useFeatureBackToBack:
|
|
greyCntr =0
|
|
redCntr =0
|
|
yellowCntr =0
|
|
allCntr=0
|
|
for (d1,d2) in critical_day_pairs:
|
|
print ("no time zone crossings for at days " , getNiceDay[d1],"->",getNiceDay[d2],nextCritical[d2])
|
|
for t in realteams:
|
|
if currentLocation[(t,d1)] and currentLocation[(t,d2)] :
|
|
t1 = currentLocation[(t,d1)]
|
|
t2 = currentLocation[(t,d2)]
|
|
allCntr+=1
|
|
if (t2,1.0) in bad_travel_out[t1]:
|
|
print ("GREY BACK TO BACK FOUND IN TOUR :", getNiceDay[d1] ,getTeamById[t] , " -> " , getTeamById[t1] , " -> " , getTeamById[t2] )
|
|
greyCntr +=1
|
|
if (t2,0.05) in bad_travel_out[t1]:
|
|
print ("RED BACK TO BACK FOUND IN TOUR :", getNiceDay[d1] ,getTeamById[t] , " -> " , getTeamById[t1] , " -> " , getTeamById[t2] )
|
|
redCntr +=1
|
|
if (t2,0.003) in bad_travel_out[t1]:
|
|
print ("YELLOW BACK TO BACK FOUND IN TOUR :", getNiceDay[d1] ,getTeamById[t] , " -> " , getTeamById[t1] , " -> " , getTeamById[t2] )
|
|
yellowCntr +=1
|
|
|
|
print ("badBackToBack_Total ", badBackToBack_Total.value())
|
|
b2bvios = [(getTeamById[t],getNiceDay[d], int(0.5+badBackToBack[(t,d)].value())) for t in teams for d in days if (t,d) in badBackToBack.keys() and badBackToBack[(t,d)].value()>0.1 ]
|
|
greenB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==1]
|
|
yellowB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==3]
|
|
redB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==50]
|
|
greyB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==1000]
|
|
print ( len(greyB2B) , " + ",len(redB2B) , " + ",len(yellowB2B) , " + ",len(greenB2B))
|
|
print ( greyCntr , " + ", redCntr , " + ", yellowCntr , " + green = ", allCntr)
|
|
print (greyB2B+redB2B)
|
|
|
|
if mathModelName=="NBA":
|
|
print ("badRepeater_Total_NBA ", badRepeater_Total_NBA.value())
|
|
print ("tooLongTrip_Total_NBA ", tooLongTrip_Total_NBA.value())
|
|
print ("eastWestTrip_Total_NBA ", eastWestTrip_Total_NBA.value())
|
|
|
|
newRounds = []
|
|
if impType != 'INIT':
|
|
localSearchResults.append(newLSR)
|
|
|
|
LocalSearchResult.objects.bulk_create(localSearchResults)
|
|
|
|
mipgap=0.05
|
|
|
|
if thisSeason.useFeatureKickOffTime and not evalRun:
|
|
for (t1,t2) in games :
|
|
for rd in roundDays:
|
|
if getVal(x[(t1,t2,rd)]) >0.99:
|
|
model2+= x[(t1,t2,rd)]==1
|
|
for tm in times:
|
|
makeIntVar(x_time[(t1,t2,rd,tm)])
|
|
# makeIntVar(x_time[(t1,t2,rd,getIdByTime["Early"])])
|
|
|
|
writeProgress("Refining times ", thisScenario.id , 99)
|
|
|
|
print ("######################")
|
|
print ("## REFINING TIMES ####")
|
|
print ("######################")
|
|
|
|
if solver == "CBC":
|
|
model2.solve(PULP_CBC_CMD(fracGap = mipgap, maxSeconds = 600, threads = 8,msg=1))
|
|
elif solver == "Gurobi":
|
|
# mipgap = 1.0
|
|
model2.solve(GUROBI(MIPGap=mipgap, TimeLimit=600))
|
|
else:
|
|
try:
|
|
model2.solve(XPRESS(msg=1,maxSeconds = 60, targetGap=mipgap ,options=["THREADS=12"], keepFiles=True))
|
|
except:
|
|
model2.status = pulp.LpStatusNotSolved
|
|
|
|
if model2.status<0 or not value(model2.objective):
|
|
if solver != "xpress" or not value(model2.objective):
|
|
writeProgress("Model could not be solved within " + str(maxTime)+" seconds ....", thisScenario.id,0)
|
|
if RUN_ENV == 'celery' and task:
|
|
print({'timestamp':time.time(),'objective':-1, "user ": user_name, "league ": str(thisLeague)})
|
|
else:
|
|
print('Model could not be solved')
|
|
|
|
if RUN_ENV == 'celery' and task:
|
|
task.update_state(state='Reopt Rounds', meta={'timestamp':time.time(),'objective':value(model2.objective), "user ": user_name, "league ": str(thisLeague)})
|
|
|
|
# %%
|
|
|
|
broadcastingResult,networks_by_game = optimize_model3 (optCameraMovement)
|
|
|
|
# for (t,d) in tvkitproblem.keys():
|
|
# if getVal(tvkitproblem[(t,d)])>0.1:
|
|
# print ("TVKIT PROBLEM " , getTeamById[t], getNiceDay[d])
|
|
|
|
succ2={(t1,d1) : (t2,d2) for (t1,d1,t2,d2) in move2.keys() if getVal(move2[(t1,d1,t2,d2)])>0.1 }
|
|
for (t1,d1,t2,d2) in move2.keys():
|
|
if getVal(move2[(t1,d1,t2,d2)])>0.1:
|
|
# print ("MOVING " , getTeamById[t1], getNiceDay[d1] , " --> " , getTeamById[t2], getNiceDay[d2] , " : " ,getVal(move2[(t1,d1,t2,d2)]) , " ", distanceById[t1,t2])
|
|
# tv_dist+=distanceById[t1,t2]
|
|
succ2[(t1,d1)]=(t2,d2)
|
|
|
|
tv_dist=0.0
|
|
for (t,d) in newtrip2.keys():
|
|
if getVal(newtrip2[(t,d)])>0.1:
|
|
print ("NEW TRIP STARTING " , getTeamById[t], getNiceDay[d])
|
|
t1,d1=t,d
|
|
while (t1,d1) in succ2.keys():
|
|
t2,d2=succ2[t1,d1]
|
|
tv_dist+=distanceById[t1,t2]
|
|
print (" --> " , getTeamById[t2], getNiceDay[d2] , " : " ,getVal(move2[(t1,d1,t2,d2)]) , " ", distanceById[t1,t2])
|
|
t1,d1=succ2[t1,d1]
|
|
|
|
jamshedpurVios = [ d for d in jamshedpurVio.keys() if getVal(jamshedpurVio[d])>0.1]
|
|
for d in jamshedpurVios:
|
|
print("jamshedpurVios : " ,getNiceDay[d])
|
|
|
|
|
|
print ("total distance by tv teams" ,tv_dist )
|
|
|
|
sol_quality='<div class="row"><div class="col-lg-5"><div class="ibox"><div class="ibox-title"><h5> '+_('Summary')+' </h5></div><div class="ibox-content"><table class="table table-striped">'
|
|
sol_solution=""
|
|
sol_kpis=""
|
|
sol_broadcasting=""
|
|
sol_special_wishes=""
|
|
|
|
print ("sol_kpis : ", sol_kpis)
|
|
|
|
weekdays = wds.values()
|
|
weekDayDistributionHome={ (t,w) : 0 for t in teams for w in weekdays }
|
|
weekDayDistributionAway={ (t,w) : 0 for t in teams for w in weekdays }
|
|
getNiceDayOfGameByRound={ (t1,t2,r) : '' for t1 in teams for t2 in teams for r in rounds}
|
|
# getNiceDayOfGameByRound={}
|
|
t_games = { t: [] for t in teams}
|
|
game_ko_time ={}
|
|
sol_schedule='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-title"><h5> '+_('Schedule')+' </h5></div><div class="ibox-content">'
|
|
sol_schedule="<table id='listview' class='display table-bordered table-hover'><thead><tr>"
|
|
if thisSeason.useFeatureGameIDs:
|
|
sol_schedule+="<th>ID</th>"
|
|
sol_schedule+="<th>"+_('Match Day')+"</th>"
|
|
if thisSeason.groupBased:
|
|
sol_schedule+="<th>"+_('Group')+"</th>"
|
|
sol_schedule+="<th>"+_('Date')+"</th>"
|
|
if thisSeason.useFeatureKickOffTime or sharedStadiums:
|
|
if thisSeason.league.sport=="Hockey" :
|
|
sol_schedule+="<th>"+_('Face-Off')+"</th>"
|
|
elif thisSeason.league.sport=="Basketball" :
|
|
sol_schedule+="<th>"+_('Tip-Off')+"</th>"
|
|
else :
|
|
sol_schedule+="<th>"+_('Kick-Off')+"</th>"
|
|
|
|
if sharedStadiums:
|
|
sol_schedule+="<th>"+_('Stadium')+"</th>"
|
|
|
|
sol_schedule+="<th>"+_('Home')+"</th><th>"+_('Away')+"</th>"
|
|
|
|
if sharedStadiums:
|
|
sol_schedule+="<th>"+_('Home Short')+"</th><th>"+_('Away Short')+"</th>"
|
|
|
|
if thisLeague.name in ["Indian Super League 2021"]:
|
|
sol_schedule+="<th>"+_('Stadium')+"</th>"
|
|
sol_schedule+="<th>"+_('Rest Days Home')+"</th>"
|
|
sol_schedule+="<th>"+_('Rest Days Away')+"</th>"
|
|
last_played = {
|
|
t : 0 for t in realteams
|
|
}
|
|
if thisSeason.useFeatureBroadcasting:
|
|
sol_schedule+="<th>"+_('Broadcasting')+"</th>"
|
|
if thisSeason.useFeaturePrediction:
|
|
sol_schedule+="<th>"+_('Estimated Attendance')+"</th>"
|
|
sol_schedule+="<th>"+_('Distance')+"</th></tr></thead><tbody>"
|
|
|
|
getGameID={}
|
|
gameID = thisSeason.firstGameID
|
|
for (t1,t2,r,d2) in currentSolution :
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-':
|
|
getGameID[(t1,t2,r,d2)]=gameID
|
|
gameID+=1
|
|
|
|
gameID = thisSeason.firstGameID
|
|
print (currentSolution)
|
|
|
|
if sharedStadiums :
|
|
usedStadiumTimeSlot = { (t,d) : getStadiumTimeSlot[s] for (t,d,s) in useStadiumTimeSlot.keys() if useStadiumTimeSlot[(t,d,s)].value()!=None and useStadiumTimeSlot[(t,d,s)].value() >0.9}
|
|
|
|
# print (stadium_name)
|
|
|
|
getTimeOfGame = {}
|
|
|
|
for d in daysSorted:
|
|
sol_schedule_late=""
|
|
for (t1,t2,r,d2) in currentSolution :
|
|
gm_time = ""
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
if t1 in realteams and t2 in realteams and getVal(x_time[(t1,t2,(r,d2),tm)]) >=0.9:
|
|
gm_time=tm
|
|
|
|
if mathModelName=="UEFA" :
|
|
if t1 in realteams and t2 in realteams and getVal(x_time[(t1,t2,(r,d2),getIdByTime["Early"])]) >=0.9:
|
|
gm_time="18:45"
|
|
else:
|
|
gm_time="21:00"
|
|
|
|
if toTime :
|
|
gm_time=toTime[t_country[t1],d2][0]
|
|
# gm12="<b>"+ toTime[t_country[t1],d][0] + "</b><br>"
|
|
if len(toTime[t_country[t1],d2])>1:
|
|
toTime[t_country[t1],d2].pop(0)
|
|
|
|
if sharedStadiums :
|
|
if nonIceGame[(t1,d2)].value()>0.5:
|
|
gm_time= " --- "
|
|
else:
|
|
if (t1, usedStadiumTimeSlot[(t1,d2)]['id']) not in stadiumTimeSlotPref.keys() :
|
|
gm_time= str(usedStadiumTimeSlot[(t1,d2)]['start'])+ " ("+str(usedStadiumTimeSlot[(t1,d2)]['id'])+")"
|
|
else:
|
|
gm_time= str(usedStadiumTimeSlot[(t1,d2)]['start'])+ " (" + stadiumTimeSlotPref[(t1, usedStadiumTimeSlot[(t1,d2)]['id'])].prio +")"
|
|
gm_stadium=getSharedStadiumName[usedStadiumTimeSlot[(t1,d2)]['stadium_id']]
|
|
|
|
|
|
game_ko_time[(t1,t2,r,d2)]=gm_time
|
|
# print (getTeamById[t1], getTeamById[t2], gm_time)
|
|
|
|
if d2==d :
|
|
t_games[t2].append((d,t1,"A"))
|
|
t_games[t1].append((d,t2,"H"))
|
|
isLate = False
|
|
sol_schedule_tmp=""
|
|
getNiceDayOfGameByRound[(t1,t2,getRoundByDay[d])]=getNiceDay[d]
|
|
# print (str(d) , ' : ', str(t1) , ' - ' , str(t2) , ' ' , str(x[(t1,t2,(r,d2))].value()) )
|
|
networks_by_game_string =''
|
|
networkIds_by_game_string =''
|
|
for n in networks_by_game[(t1,t2,d)]:
|
|
networks_by_game_string+=networkName[n]+ ', '
|
|
networkIds_by_game_string+=str(n)+ ';'
|
|
if networks_by_game_string!="":
|
|
networks_by_game_string=networks_by_game_string[:-2]
|
|
if networkIds_by_game_string!="":
|
|
networkIds_by_game_string=networkIds_by_game_string[:-1]
|
|
else:
|
|
networkIds_by_game_string="None"
|
|
if gm_time not in times:
|
|
networks_by_game_string+= gm_time
|
|
|
|
star1= ''
|
|
star2= ''
|
|
if len(countries)>1:
|
|
if t_country[t1]!= "" and t_country[t1]!= getTeamById[t1] :
|
|
star1=" ("+t_country[t1]+")"
|
|
if t_country[t2]!= "" and t_country[t2]!= getTeamById[t2]:
|
|
star2=" ("+t_country[t2]+")"
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-' :
|
|
sol_schedule_tmp+='<tr>'
|
|
if thisSeason.useFeatureGameIDs:
|
|
getGameID[(t1,t2,r,d2)]=gameID
|
|
sol_schedule_tmp+='<td>'+ str(getGameID[(t1,t2,r,d2)]) +'</td>'
|
|
gameID+=1
|
|
sol_schedule_tmp+='<td>'+ str(r) +'</td>'
|
|
if thisSeason.groupBased and t_conference[t1]!=0:
|
|
sol_schedule_tmp+="<th>" + t_conference[t1].name + "</th>"
|
|
sol_schedule_tmp+='<td data-sort='+getDateTimeDay[d].strftime("%Y-%m-%d")+'>'+ getNiceDay[d] +'</td>'
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
if (t1,t2,(r,d2),tm) in x_time.keys() and getVal(x_time[(t1,t2,(r,d2),tm)]) > 0.1 :
|
|
sol_schedule_tmp+='<td>'+getTimeById[tm]+'</td>'
|
|
if "Late" in getIdByTime.keys() and tm==getIdByTime["Late"]:
|
|
isLate = True
|
|
|
|
if sharedStadiums:
|
|
sol_schedule_tmp+='<td>'+gm_time+'</td>'
|
|
sol_schedule_tmp+='<td>'+gm_stadium+'</td>'
|
|
|
|
sol_schedule_tmp+='<td>'+ getTeamById[t1] + star1+'</td><td>'+ getTeamById[t2] + star2+'</td>'
|
|
|
|
if sharedStadiums:
|
|
sol_schedule_tmp+='<td>'+ t_shortname[t1] + '</td><td>'+ t_shortname[t2] + '</td>'
|
|
|
|
if thisLeague.name in ["Indian Super League 2021"]:
|
|
sol_schedule_tmp+="<td>"+getStadiumById[t1]+"</td>"
|
|
if last_played[t1] == 0:
|
|
sol_schedule_tmp+="<td>-</td>"
|
|
else:
|
|
sol_schedule_tmp+="<td>"+str((getDateTimeDay[d]-getDateTimeDay[last_played[t1]]).days-1)+"</td>"
|
|
if last_played[t2] == 0:
|
|
sol_schedule_tmp+="<td>-</td>"
|
|
else:
|
|
sol_schedule_tmp+="<td>"+str((getDateTimeDay[d]-getDateTimeDay[last_played[t2]]).days-1)+"</td>"
|
|
last_played[t1] = d
|
|
last_played[t2] = d
|
|
|
|
if thisSeason.useFeatureBroadcasting:
|
|
sol_schedule_tmp+='<td>'+ networks_by_game_string +'</td>'
|
|
if thisSeason.useFeaturePrediction:
|
|
sol_schedule_tmp+='<td>'+ str(attendance[t1,t2,d]) +'</td>'
|
|
sol_schedule_tmp+='<td>'+ scaledDistanceString(distance[getTeamById[t1],getTeamById[t2]])
|
|
if distance[getTeamById[t1],getTeamById[t2]]<=thisSeason.maxDistanceDerby :
|
|
sol_schedule_tmp+=' (D)'
|
|
sol_schedule_tmp+='</td></tr>'
|
|
if isLate:
|
|
sol_schedule_late+=sol_schedule_tmp
|
|
else:
|
|
sol_schedule+=sol_schedule_tmp
|
|
chosenTime = "None"
|
|
if thisSeason.useFeatureKickOffTime:
|
|
for tm in times:
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-' and (t1,t2,(r,d2),tm) in x_time.keys() and getVal(x_time[(t1,t2,(r,d2),tm)]) > 0.1 :
|
|
chosenTime = getTimeById[tm]
|
|
getTimeOfGame[(t1,t2,d2)]=tm
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-':
|
|
sol_solution+=str(d)+'_'+str(t1)+'_'+str(t2)+'_'+str(r)+'_'+chosenTime+'_'+str(getGameID[(t1,t2,r,d)])+'_'+networkIds_by_game_string+'__'
|
|
if getWeekDay[d] != '' and t1 in realteams and t2 in realteams:
|
|
weekDayDistributionHome[(t1, getWeekDay[d])] +=1
|
|
weekDayDistributionAway[(t2, getWeekDay[d])] +=1
|
|
sol_schedule+= sol_schedule_late
|
|
sol_schedule+= '</tbody></table>'
|
|
|
|
for t in teams:
|
|
t_games[t]=sorted(t_games[t],key=lambda at: getDateTimeDay[at[0]])
|
|
|
|
cntr=0
|
|
sol_breaks='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_breaks+="<table id='example' class='display table-bordered table-hover'><thead><tr><th>"+_('First Round')+"</th><th>"+_('Second Round')+"</th><th>"+_('Home-Break')+"</th><th>"+_('Away-Break')+"</th></tr></thead><tbody>"
|
|
for bl in breaks :
|
|
homes =""
|
|
aways =""
|
|
for t in realteams:
|
|
if breakVio[(bl['id'],t)].value()>0.9 and homeInRound[(t,bl['round1'])].value() > 0.9:
|
|
homes += getTeamById[t]+ ", "
|
|
cntr+=1
|
|
if breakVio[(bl['id'],t)].value()>0.9 and awayInRound[(t,bl['round1'])].value() > 0.9:
|
|
aways += getTeamById[t]+ ", "
|
|
cntr+=1
|
|
sol_breaks+='<tr><td>'+ str(bl['round1']) +'</td><td>'+ str(bl['round2']) +'</td><td>'+ homes[:-2]+'</td><td>'+ aways[:-2]+'</td></tr>'
|
|
sol_breaks+='</tbody></table></div></div></div></div>'
|
|
|
|
cntr=0
|
|
first=0
|
|
sol_breaks+='___'
|
|
|
|
print ("sol_kpis : ", sol_kpis)
|
|
|
|
|
|
for bl in breaks :
|
|
home_ids = ''
|
|
away_ids = ''
|
|
for t in realteams:
|
|
# print (bl['round1'], breakVio[(bl['id'],t)].value() , homeInRound[(t,bl['round1'])].value(), awayInRound[(t,bl['round1'])].value(), getTeamById[t] )
|
|
if breakVio[(bl['id'],t)].value()>0.9 and homeInRound[(t,bl['round1'])].value() > 0.9:
|
|
home_ids += str(t) + '-'
|
|
cntr+=1
|
|
if breakVio[(bl['id'],t)].value()>0.9 and awayInRound[(t,bl['round1'])].value() > 0.9:
|
|
away_ids += str(t) + '-'
|
|
cntr+=1
|
|
# print (bl, ' ' , str(t) )
|
|
if (home_ids[:-2] != '') or (away_ids[:-2] != ''):
|
|
if first > 0:
|
|
sol_breaks+= '---'
|
|
sol_breaks+=str(bl['round1']) + '_' + str(bl['round2']) + '_' + home_ids[:-1] + 'x' + away_ids[:-1]
|
|
first=1
|
|
|
|
|
|
sol_kpis+=""+_('Breaks')+"__"+ str(cntr)+"___"
|
|
|
|
sol_pairings=''
|
|
if thisSeason.useFeaturePairings:
|
|
violation_str = defaultdict(lambda:"")
|
|
kpi_text="<table>"
|
|
cntr=0
|
|
sol_pairings='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_pairings+="<table id='example' class='display table-bordered table-hover'><thead><tr><th>"+_('Team')+" 1</th><th>"+_('Team')+" 2</th><th>"+_('Day')+"</th><th>"+_('Type')+"</th><th>"+_('Dist')+"</th><th>"+_('Prio')+"</th></tr></thead><tbody>"
|
|
for d in days+higherLeagueDayIds:
|
|
for pair in pairings :
|
|
ds = "do not play both on same day"
|
|
if pair['dist']==1:
|
|
ds = "do not play both within two successive days"
|
|
if pair['dist']==2:
|
|
ds = "do not play both at the same time"
|
|
if pair['dist']==3:
|
|
ds = "do not play both in the same round"
|
|
if pair['dist']==4:
|
|
ds = "play both on same day"
|
|
if pair['dist']==6:
|
|
ds = "play both at the same time"
|
|
if pair['dist']==7:
|
|
ds = "play both in the same round"
|
|
if pairingVio[(pair['id'],d)].value()>0.9 :
|
|
# if pairingVio[(pair['id'],d)].value()>0.9 and sum( getVal(home[t,d]) + getVal(away[t,d]) for t in [pair['team1_id'],pair['team2_id']]) >0.9 :
|
|
sol_pairings+='<tr><td>'+ str(getTeamById[pair['team1_id']]) +'</td><td>'+ str(getTeamById[pair['team2_id']]) +'</td><td>'+ str(getNiceDay[d]) +'</td><td>'+ str(pair['type']) +'</td><td>'+ ds +'</td><td>'+ str(pair['prio']) +'</td>'
|
|
violation_str[pair['id']] += str(getNiceDay[d]) +"__"
|
|
kpi_text+='<tr><td> '+ str(getNiceDay[d]) +'</td><td>'+ str(getTeamById[pair['team1_id']]).replace("'","") +'</td><td> - </td><td>'+ str(getTeamById[pair['team2_id']]).replace("'","") +'</td>'
|
|
# kpi_text+='<tr><td> '+ str(getNiceDay[d]) +'</td><td>'+ str(getTeamById[pair['team1_id']]).replace("'","") +'</td><td> - </td><td>'+ str(getTeamById[pair['team2_id']]).replace("'","") +' </td><td>'+ ds +' '+ str(pair['type']) +'</td>'
|
|
cntr+=1
|
|
|
|
kpi_text+="</table>"
|
|
sol_pairings+='</tbody></table></div></div></div></div>'
|
|
print (sol_pairings)
|
|
sol_kpis+=""+_('Violated Pairings')+"__"+ str(cntr)+"__"+ kpi_text+"___"
|
|
|
|
Pairing.objects.filter(scenario=thisScenario).update(violation='')
|
|
for pair in Pairing.objects.filter(id__in=violation_str.keys()):
|
|
pair.violation = violation_str[pair.id][:-2]
|
|
pair.save()
|
|
|
|
sol_distance_saved=0.0
|
|
sol_trips='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_trips+="<table id='example' class='display table-bordered table-hover'><thead><tr><th>"+_('Team')+"</th><th>"+_('Destinations')+"</th><th>"+_('Trip Length')+"</th><th>"+_('Distance saved')+"</th></tr></thead><tbody>"
|
|
print(teams)
|
|
print(rounds)
|
|
print(clusters)
|
|
currentTrip=''
|
|
totalDistanceTravelled = {t : 0.0 for t in teams }
|
|
|
|
cntr=0
|
|
for t in teams:
|
|
print ("new Team" , getTeamById[t] )
|
|
currentTrip += 'getTrips["'+getTeamById[t] +'"]=[';
|
|
lastDay = False
|
|
curTrip = []
|
|
theseTrips = []
|
|
for (thisDay,thisTeam,ha) in t_games[t]:
|
|
# print ("checking " ,thisDay,thisTeam , getNiceDay[thisDay])
|
|
if lastDay:
|
|
if getDateTimeDay[thisDay] - getDateTimeDay[lastDay] > datetime.timedelta(days=thisSeason.maxDistanceWithinTrip+1) or ha=="H":
|
|
if len(curTrip)>=1:
|
|
theseTrips.append(curTrip)
|
|
# print ("new trip ", curTrip)
|
|
curTrip = []
|
|
if ha=="A":
|
|
curTrip.append((thisDay,thisTeam))
|
|
lastDay=thisDay
|
|
|
|
if len(curTrip)>0:
|
|
theseTrips.append(curTrip)
|
|
|
|
if len(theseTrips) >0:
|
|
realTripFound= False
|
|
for curTrip in theseTrips:
|
|
c_sav = sum([ distanceById[t,curTrip[i-1][1] ] + distanceById[t,curTrip[i][1] ] - distanceById[curTrip[i-1][1],curTrip[i][1] ] for i in range(1,len(curTrip)) ])
|
|
c_tot = 2*sum([ distanceById[t,curTrip[i][1]] for i in range(len(curTrip))]) - c_sav
|
|
totalDistanceTravelled[t] += c_tot
|
|
sol_distance_saved += c_sav
|
|
if len (curTrip)>1:
|
|
realTripFound=True
|
|
currentTrip += '[';
|
|
sol_trips+='<tr><td>'+ getTeamById[t] + '</td><td>'
|
|
lastTeam=False
|
|
for (thisDay,thisTeam) in curTrip:
|
|
wantedTrip = ""
|
|
for (tt,tv1,tv2,tv3,tv4) in tripElements[t]:
|
|
# print ("")
|
|
# print (tt," - " ,tv1,tv2,tv3,tv4 )
|
|
for (tt1,tt2) in [(tv1,tv2), (tv2,tv3), (tv3,tv4)] :
|
|
# if lastTeam in tt1 or thisTeam in tt2:
|
|
# print ( lastTeam , " in " , tt1 ," -- ", thisTeam , " in " , tt2, lastTeam in tt1 and thisTeam in tt2)
|
|
if lastTeam in tt1 and thisTeam in tt2:
|
|
wantedTrip = "*"
|
|
print ( " ", getNiceDay[thisDay] , getTeamById[lastTeam] ," -> ", getTeamById[thisTeam] , " added ")
|
|
lastTeam=thisTeam
|
|
currentTrip+= '"'+ getTeamById[thisTeam] +'",'
|
|
sol_trips+= ' <span style="display:inline-block;width:170px"> '+getNiceDay[thisDay] + " : </span> " + getTeamById[thisTeam] + " "+ wantedTrip+"<br>"
|
|
sol_trips=sol_trips[:-4]
|
|
sol_trips+='</td><td>'+ scaledDistanceString(c_tot) + '</td><td colspan='+str(len(curTrip))+'>'+ scaledDistanceString(c_sav) + '</td>'
|
|
cntr+=1
|
|
sol_trips+='</tr>'
|
|
currentTrip=currentTrip[:-1]
|
|
currentTrip += '],';
|
|
if realTripFound:
|
|
currentTrip=currentTrip[:-1]
|
|
currentTrip += '];\n';
|
|
|
|
sol_trips+='</tbody></table></div></div></div></div>'
|
|
sol_trips+='<script>'+currentTrip+'</script>'
|
|
|
|
if thisSeason.useFeatureTrips:
|
|
travelSum=sum([totalDistanceTravelled[t] for t in teams])
|
|
if sol_distance_saved+travelSum >0:
|
|
percentAgeSaved= int(sol_distance_saved/(sol_distance_saved+travelSum)*100)
|
|
else :
|
|
percentAgeSaved= 0
|
|
sol_kpis+=""+_('Num. Trips')+"__"+ str(cntr)+"___"
|
|
sol_kpis+=""+_('Distance Traveled')+"__"+ scaledDistanceString(travelSum)+"___"
|
|
sol_kpis+=""+_('Distance saved on trips')+"__"+ scaledDistanceString(sol_distance_saved)+" (" + str(percentAgeSaved) + "%)___"
|
|
|
|
currentSolutionOfDay = { d: [] for d in days }
|
|
currentSolutionDayOfTeamRound = { (t,r) : 0 for t in teams for r in rounds }
|
|
for (t1,t2,r,d) in currentSolution:
|
|
currentSolutionOfDay[d].append((t1,t2,r))
|
|
currentSolutionDayOfTeamRound[(t1,r)]= d
|
|
currentSolutionDayOfTeamRound[(t2,r)]= d
|
|
|
|
redStripes = ''
|
|
for bl in breaks :
|
|
for t in realteams:
|
|
if breakVio[(bl['id'],t)].value()>0.9 :
|
|
# print ("Break for " , getTeamById[t] , ' from ', currentSolutionDayOfTeamRound[(t,bl['round1'])] , ' to ' , currentSolutionDayOfTeamRound[(t,bl['round2'])] )
|
|
redStripes+= '"'+str(t)+'_'+str(currentSolutionDayOfTeamRound[(t,bl['round1'])]) +'__'+str(t)+'_'+str(currentSolutionDayOfTeamRound[(t,bl['round2'])]) +'", '
|
|
|
|
cntr={ t : 0 for t in ["Home", "Away",'Hide']}
|
|
|
|
blockobjects = []
|
|
kpi_text={ ha : "<table>" for ha in ['Home','Away','Hide']}
|
|
for bl in blockings :
|
|
if (blockingVio[bl['id']].value()>0.9) :
|
|
cntr[bl['type']]+=1
|
|
kpi_text[bl['type']]+= "<tr><td> "+ getTeamById[bl['team_id']].replace("'","") +"</td><td>" + getDayById[bl['day_id']]['day'] +" </td></tr>"
|
|
kpi_text["Home"]+= "</table>"
|
|
kpi_text["Away"]+= "</table>"
|
|
|
|
sol_kpis+=_('Violated Blockings')+"__"+ str(cntr['Home'])+ ' of '+ str(nBlockingHome) +"__"+ kpi_text['Home'] +"___"
|
|
|
|
if thisSeason.useFeatureNoTravel:
|
|
sol_kpis+=_('Violated Travel Restrictions')+'__'+ str(cntr['Away'])+ ' of '+ str(nBlockingAway) +"__"+ kpi_text['Away'] + '___'
|
|
|
|
cntr=0
|
|
kpi_text="<table>"
|
|
for st in stadiums :
|
|
for d in days+higherLeagueDayIds:
|
|
if tooManyHomesInStadium[(st, d)].value()>0.9:
|
|
kpi_text+= "<tr><td> "+ stadium_name[st] +"</td><td>" + getDayById[d]['day'] +" </td></tr>"
|
|
cntr+=1
|
|
kpi_text+="</table>"
|
|
|
|
if cntr==0 and len(stadiums)==0:
|
|
cntr="0 of 0"
|
|
|
|
sol_kpis+=_('Overbooked stadiums')+'__'+ str(cntr)+ "__"+ kpi_text + '___'
|
|
|
|
displayVios = { i: str(i) for i in range(100) }
|
|
displayVios[-1]="--"
|
|
cntr=0
|
|
wishobjects = []
|
|
kpi_text=""
|
|
for haw in hawishes :
|
|
# if (haw['homeAway']=='Home' and homePat[haw['team_id'], getDayById[haw['day_id']]['round']].value()<0.1) or (haw['homeAway']=='Away' and homePat[haw['team_id'], getDayById[haw['day_id']]['round']].value()>0.9) :
|
|
violtext =""
|
|
if haw['forOneDay'] :
|
|
relTeamString = { el : getStringFromSet(elemHaWishTeams[el]) for el in elemHaWishes[haw['id']] }
|
|
relTeams = set([ relTeamString[el] for el in elemHaWishes[haw['id']]])
|
|
# print ("\n", relTeams )
|
|
# for rt in relTeams:
|
|
# print (hawOneVio[(haw['id'],rt)].value())
|
|
if (gew['Home-/Away']>0 and hawVio[haw['id']].value()>0.9 ) :
|
|
violtext =""+_('Not fulfilled')+""
|
|
if haw['forEachTeam'] :
|
|
violtext +=":"
|
|
relTeamString = { el : getStringFromSet(elemHaWishTeams[el]) for el in elemHaWishes[haw['id']] }
|
|
relTeams = set([ relTeamString[el] for el in elemHaWishes[haw['id']]])
|
|
# print ("\n", relTeams )
|
|
for rt in relTeams:
|
|
# print (hawOneVio[(haw['id'],rt)].value())
|
|
if hawOneVio[(haw['id'],rt)].value()>0.9:
|
|
for rr in rt.split("_"):
|
|
violtext+="<br>"+ getTeamById[int(rr)]
|
|
cntr+=1
|
|
else:
|
|
cntr+=1
|
|
|
|
|
|
else:
|
|
for el in elemHaWishes[haw['id']]:
|
|
if (gew['Home-/Away']>0 and HawVioTooMuch[el].value()+HawVioTooLess[el].value()>0.9 ) :
|
|
who=''
|
|
if haw['forEachTeam']:
|
|
who = getTeamById[elemHaWishTeams[el][0]] + ': '
|
|
if haw['forEachDay']:
|
|
who = getNiceDay[elemHaWishDays[el][0]]
|
|
if haw['timeframe']!=0:
|
|
# day1= parse(getDayById[elemHaWishDays[el][0]]['day'])
|
|
day1= getDateTimeDay[elemHaWishDays[el][0]]
|
|
day2= day1 + datetime.timedelta(days=haw['timeframe']-1)
|
|
# print ( day1, day2)
|
|
if haw['timeframe']>0 and day2!=day1:
|
|
who += " - "+str(day2.strftime('%a, %b %d, %Y'))
|
|
who +=": "
|
|
if (HawVioTooLess[el].value()>0.9) :
|
|
violtext += who + str(int(HawVioTooLess[el].value() +0.1)) + " too few<br>"
|
|
if (HawVioTooMuch[el].value()>0.9) :
|
|
violtext += who + str(int(HawVioTooMuch[el].value() +0.1)) + " too many<br>"
|
|
# print ( "HAW TOO MANY ", haw, elemHaWishTeams[el] , elemHaWishDays[el] , el)
|
|
# for ddd in elemHaWishDays[el]:
|
|
# print (" - day ", getDayById[ddd])
|
|
# for ddd in elemHaWishTeams[el]:
|
|
# print (" - team ", getTeamById[ddd])
|
|
cntr+=1
|
|
if violtext != "":
|
|
kpi_text += haw['reason'].replace("'","") +"<br>"
|
|
|
|
dy=''
|
|
if haw['day_id']:
|
|
dy += getNiceDay[haw['day_id']]
|
|
if haw['day2_id']:
|
|
dy += ' - ' +getNiceDay[haw['day2_id']]
|
|
if not haw['weekdays'] in ['--', '-'] :
|
|
if haw['day_id'] or haw['day2_id']:
|
|
dy += ', '
|
|
dy += haw['weekdays']
|
|
|
|
if violtext != haw['violation'] or hawRoundsString[haw['id']]!=haw['affected_rounds']:
|
|
wishobj = HAWish.objects.filter(id=haw['id']).first()
|
|
if wishobj:
|
|
wishobj.violation = violtext
|
|
wishobj.affected_rounds = hawRoundsString[haw['id']]
|
|
wishobjects.append(wishobj)
|
|
HAWish.objects.bulk_update(wishobjects, ['violation','affected_rounds'])
|
|
if thisSeason.useFeatureHomeAway:
|
|
if kpi_text=="":
|
|
kpi_text="<table></table>"
|
|
sol_kpis+=_('Violated Home/Away Wishes')+'__'+ str(cntr)+ ' of '+ str(nElemHaWishes)+ '__' + kpi_text + '___'
|
|
|
|
cntr=0
|
|
comments = set([enc['reason'] for enc in encwishes ])
|
|
violatedEncs={ c : True for c in comments }
|
|
|
|
for enc in encwishes :
|
|
if (encVio[enc['id']].value()<0.1 and encVio[enc['id']].value()>-0.1 ) :
|
|
violatedEncs[enc['reason']]=False
|
|
|
|
# count bundles wishes (those with the same comments are considered a bundle)
|
|
commentlist = sorted(list(comments))
|
|
if '-' in commentlist:
|
|
commentlist.remove('-')
|
|
numEncWishes = len(commentlist)
|
|
violatedEncWishes = sum( violatedEncs[c] for c in commentlist)
|
|
|
|
# count other wishes
|
|
for enc in encwishes :
|
|
if enc['reason']=='-':
|
|
numEncWishes+=1
|
|
if (encVio[enc['id']].value()>0.9) :
|
|
violatedEncWishes+=1
|
|
print ('violatedEncWishes 1:' ,violatedEncWishes)
|
|
print ('numEncWishes 1:' ,numEncWishes)
|
|
violatedEncWishes=sum(encVio[enc['id']].value() for enc in encwishes )
|
|
violatedEncWishes=int(violatedEncWishes+0.1)
|
|
numEncWishes=sum(enc['minGames'] for enc in encwishes )
|
|
print ('violatedEncWishes 2:' ,violatedEncWishes)
|
|
print ('numEncWishes 2:' ,numEncWishes)
|
|
|
|
# commentlist.append('-')
|
|
totalVios =0
|
|
wishobjects = []
|
|
kpi_text=""
|
|
for enc in encwishes :
|
|
violtext =""
|
|
# violtext = str(int(encVio[enc['id']].value() +0.1)) + " too many/few"
|
|
if enc['forOneDay'] :
|
|
print ("\n\n ENCOUNTER", enc['reason'] , gew['Encounters']>0 , encVio[enc['id']].value())
|
|
# for el in elemEncWishes[enc['id']]:
|
|
# if (encVioTooMuch[el].value()+encVioTooLess[el].value()>0.9 and len(elemEncWishDays[el])>0 ) :
|
|
|
|
# for ed in encDaySets[enc['id']]:
|
|
# if len(ed)>0:
|
|
# print (ed, encForOneNotViolated[(enc['id'], ed[0])].value() )
|
|
# relWishes = [ el for el in elemEncWishes[enc['id']] if elemEncWishDays[el] == ed ]
|
|
# print ("###",ed, relWishes)
|
|
# encForOneNotViolated[(enc['id'], ed[0])]= pulp.LpVariable('encForOneNotViolated_'+str(enc['id'])+"_"+str(ed[0]), cat=pulp.LpContinuous)
|
|
# model2 += sum( encVioTooMuch[el]+encVioTooLess[el] for el in relWishes) <= 1000 * (1-encForOneNotViolated[(enc['id'], ed[0])])
|
|
# model2 += sum( encForOneNotViolated[(enc['id'], ed[0])] for ed in encDaySets[enc['id']] if len(ed)>0 ) >= 1-encVio[enc['id']]
|
|
|
|
if (gew['Encounters']>0 and encVio[enc['id']].value()>0.9 ) :
|
|
violtext =""+_('Not fulfilled')+""
|
|
totalVios += 1
|
|
print ("violtext",violtext)
|
|
else:
|
|
for el in elemEncWishes[enc['id']]:
|
|
if (encVioTooMuch[el].value()+encVioTooLess[el].value()>0.9 and len(elemEncWishDays[el])>0 ) :
|
|
when=''
|
|
if enc['forEachDay'] or enc['forOneDay'] :
|
|
when = getNiceDay[elemEncWishDays[el][0]]
|
|
if enc['timeframe']!=0:
|
|
# day1= parse(getDayById[elemEncWishDays[el][0]]['day'])
|
|
day1= getDateTimeDay[elemEncWishDays[el][0]]
|
|
day2= day1 + datetime.timedelta(days=enc['timeframe']-1)
|
|
if enc['timeframe']>1 and not enc['multidate']:
|
|
when += " - "+str(day2.strftime('%a, %b %d, %Y'))
|
|
if when !="" and not enc['useEncounterGroups'] and not enc['useGroups']:
|
|
when += " <br>"
|
|
t1,t2=elemEncWishGames[el][0]
|
|
if enc['forEachTeam1']:
|
|
when += getTeamById[t1]
|
|
if enc['forEachTeam2']:
|
|
when += " - " +getTeamById[t2]
|
|
if when !="" and not enc['useEncounterGroups'] and not enc['useGroups']:
|
|
when +="<br> "
|
|
totalVios += 1
|
|
if (encVioTooLess[el].value()>0.9) :
|
|
violtext += when + " " +str(int(encVioTooLess[el].value() +0.1)) + " too few<br><br>"
|
|
if (encVioTooMuch[el].value()>0.9) :
|
|
violtext += when + " " +str(int(encVioTooMuch[el].value() +0.1)) + " too many<br><br>"
|
|
|
|
print ("$$$$$$ violtext",violtext, enc['timeframe'],not enc['multidate'])
|
|
|
|
if violtext != "":
|
|
kpi_text += enc['reason'] + "<br>"
|
|
print (enc)
|
|
if violtext != enc['violation'] or encRoundsString[enc['id']]!=enc['affected_rounds']:
|
|
wishobj = EncWish.objects.filter(id=enc['id']).first()
|
|
if wishobj:
|
|
wishobj.violation = violtext
|
|
wishobj.affected_rounds = encRoundsString[enc['id']]
|
|
wishobjects.append(wishobj)
|
|
EncWish.objects.bulk_update(wishobjects, ['violation','affected_rounds'])
|
|
|
|
if thisSeason.useFeatureEncounters:
|
|
if kpi_text!="":
|
|
sol_kpis+=_('Violated Encounter Wishes')+'__'+ str(totalVios)+ ' of '+ str(nElemEncWishes)+ '__' + kpi_text + '___'
|
|
else:
|
|
sol_kpis+=_('Violated Encounter Wishes')+'__'+ str(totalVios)+ ' of '+ str(nElemEncWishes)+ '___'
|
|
|
|
|
|
nGames2 =sum(home[t,d].value() for t in realteams for d in days )
|
|
# print('<tr><td>Preferred Weekdays:</td><td> '+ str(int(100*(nGames2-unpreferredTotal.value())/nGames2)) + ' % </td></tr>')
|
|
if nGames2:
|
|
sol_kpis+=_('Preferred Weekdays')+'__'+ str(int(100*(nGames2-unpreferredTotal.value())/nGames2)) + ' %___'
|
|
|
|
competitionCntr=0
|
|
for (t1,t2,r,d2) in currentSolution :
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-' :
|
|
if (t1,d2) in competitions.keys() or (t2,d2) in competitions.keys() :
|
|
competitionCntr+=1
|
|
|
|
if thisSeason.useFeatureCompetitions:
|
|
if competitionCntr==0 and len(competitions.keys())==0:
|
|
competitionCntr="0 of 0"
|
|
|
|
sol_kpis+=_('Conflicts with other competitions')+'__'+ str(competitionCntr)+ '___'
|
|
|
|
if isinstance(last_objective,(int,float)):
|
|
sol_kpis+=_('Overall Quality')+'__'+ str(int(0.01+last_objective-1)) + '___'
|
|
|
|
if show_TV_markets:
|
|
cntr=0
|
|
def c_att(cntry):
|
|
return -sum([ int(t['attractivity']) for t in teamObjects if t['country']==cntry])
|
|
countries = sorted(countries, key=c_att)
|
|
global_coeff = {t['id'] : int(t['attractivity']) for t in teamObjects }
|
|
domestic_coeff = {t['id'] : int(0.1+10*(t['attractivity']-int(t['attractivity']))) for t in teamObjects }
|
|
get_games_per_country_and_day= {(c,d) : "" for c in countries for d in days }
|
|
num_home_games_per_country_and_day= {(c,d) : 0 for c in countries for d in days }
|
|
num_home_games_per_country_and_round= {(c,r) : 0 for c in countries for r in rounds }
|
|
num_higher_home_games_per_country_and_round= {(c,r) : 0 for c in countries for r in rounds }
|
|
get_games_per_day= {d : [] for d in days }
|
|
|
|
highestGlobal = { d: [ global_coeff[t1]*global_coeff[t2] for (t1,t2,r,d2) in currentSolution if d2==d ] for d in days }
|
|
highestGlobal = { d: 0 if highestGlobal[d]==[] else max(highestGlobal[d]) for d in days }
|
|
highestDomestic = { (c,d): 30 for d in days for c in countries}
|
|
|
|
|
|
for (t1,t2,r,d) in currentSolution :
|
|
get_games_per_day[d].append((t1,t2,r,d))
|
|
t1f= getTeamById[t1]
|
|
t2f= getTeamById[t2]
|
|
glob_game_coeff = global_coeff[t1]*global_coeff[t2]
|
|
domestic_game_coeff_1 = quality_of_game_dom(t1,t2)
|
|
domestic_game_coeff_2 = quality_of_game_dom(t2,t1)
|
|
|
|
gm12=""
|
|
if game_ko_time[(t1,t2,r,d)]:
|
|
gm12="<b>"+game_ko_time[(t1,t2,r,d)]+"</b><br>"
|
|
|
|
if glob_game_coeff >= 16:
|
|
gm12 += "<font color=red>" + t1f + " - <br>" + t2f + "</font><br>"
|
|
else:
|
|
gm12 += t1f + " - <br>" + t2f +"<br>"
|
|
|
|
if glob_game_coeff >= highestGlobal[d]:
|
|
gm12 += "(<font color=red>" + str(glob_game_coeff) + "</font>/"
|
|
else:
|
|
gm12 += "("+str(glob_game_coeff) +"/"
|
|
|
|
gm12_1=gm12
|
|
gm12_2=gm12
|
|
|
|
if domestic_game_coeff_1 >= highestDomestic[(t_country[t1],d)]:
|
|
gm12_1 += "<font color=red>" + str(domestic_game_coeff_1) + "</font>)<br><br>"
|
|
else:
|
|
gm12_1 += str(domestic_game_coeff_1) +")<br><br>"
|
|
|
|
if domestic_game_coeff_2 >= highestDomestic[(t_country[t2],d)]:
|
|
gm12_2 += "<font color=red>" + str(domestic_game_coeff_2) + "</font>)<br><br>"
|
|
else:
|
|
gm12_2 += str(domestic_game_coeff_2) +")<br><br>"
|
|
|
|
num_home_games_per_country_and_day[(t_country[t1],d)]+= 1
|
|
num_home_games_per_country_and_round[(t_country[t1],r)]+= 1
|
|
get_games_per_country_and_day[(t_country[t1],d)]+= gm12_1
|
|
get_games_per_country_and_day[(t_country[t2],d)]+= gm12_2
|
|
|
|
|
|
for (dy,t1,t2,r,tm) in higherGames:
|
|
if t_country[t1] in countries:
|
|
num_higher_home_games_per_country_and_round[(t_country[t1],r)]+= 1
|
|
|
|
sol_special_wishes='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<div id='chart_div'></div></div></div></div></div>"
|
|
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead><tr><th> </th>"
|
|
for d in days:
|
|
sol_special_wishes+="<th>" + getNiceDay[d] + "</th>"
|
|
sol_special_wishes+="</tr></thead><tbody>"
|
|
|
|
for c in countries:
|
|
sol_special_wishes+="<tr><td><b>" + c + "</b></td>"
|
|
for d in days:
|
|
sol_special_wishes+="<td align=center>" + get_games_per_country_and_day[(c,d)][:-8] + "</td>"
|
|
sol_special_wishes+="</tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<h2>"+_('Home Games per Country and Day')+"</h2><table class='display table-bordered table-hover'><thead><tr><th> </th>"
|
|
for d in days:
|
|
sol_special_wishes+="<th align=center>" + getNiceDay[d] + "</th>"
|
|
sol_special_wishes+="</tr></thead><tbody>"
|
|
|
|
for c in countries:
|
|
sol_special_wishes+="<tr><td><b>" + c + "</b></td>"
|
|
for d in days:
|
|
sol_special_wishes+="<td align=center>" + str(num_home_games_per_country_and_day[(c,d)]) + "</td>"
|
|
sol_special_wishes+="</tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
|
|
|
|
print ("higherGames ", higherGames)
|
|
print ("len(higherGames)>0", len(higherGames))
|
|
|
|
also_count_highergames = len(higherGames)>0
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<h2>Home Games per Country and Week </h2><table class='display table-bordered table-hover'><thead><tr><th> </th>"
|
|
for r in rounds:
|
|
sol_special_wishes+="<th align=center>" + str(r) + "</th>"
|
|
sol_special_wishes+="</tr></thead><tbody>"
|
|
|
|
for c in countries:
|
|
sol_special_wishes+="<tr><td><b>" + c + "</b></td>"
|
|
for r in rounds:
|
|
sol_special_wishes+="<td align=center>" + str(num_home_games_per_country_and_round[(c,r)])
|
|
if also_count_highergames:
|
|
sol_special_wishes+= " + " + str(num_higher_home_games_per_country_and_round[(c,r)]) + " = <b>" + str(num_home_games_per_country_and_round[(c,r)]+num_higher_home_games_per_country_and_round[(c,r)]) + "</b>"
|
|
sol_special_wishes+="</td>"
|
|
sol_special_wishes+="</tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
def g_tms(ttrd):
|
|
return game_ko_time[ttrd]
|
|
for d in days:
|
|
get_games_per_day[d]= sorted(get_games_per_day[d], key=g_tms)
|
|
|
|
# # Avoid early matches with a global coefficient of 16 and more (60)
|
|
# +0.6*sum([quality_of_game(t1,t2) * x_time[(t1,t2,rd,getIdByTime["Early"])]
|
|
|
|
if mathModelName=="UEFA" :
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><tbody>"
|
|
nCols = min([len(getDays[r]) for r in rounds])
|
|
for r in rounds:
|
|
sol_special_wishes+='<tr><td colspan='+ str(5*nCols)+ '><b>Matchday ' + str(r) + '</b></td></tr> '
|
|
sol_special_wishes+='<tr>'
|
|
for d in getDays[r]:
|
|
sol_special_wishes+='<td colspan=4><b>Day ' + getNiceDay[d] + '</b></td> <td> </td> '
|
|
sol_special_wishes+='</tr>'
|
|
nRows= max([len(get_games_per_day[d]) for d in days ])
|
|
for i in range(nRows):
|
|
sol_special_wishes+='<tr >'
|
|
for d in getDays[r]:
|
|
if i>=len(get_games_per_day[d]):
|
|
sol_special_wishes+='<td colspan=4> <td>'
|
|
else:
|
|
t1,t2,r2,d2=get_games_per_day[d][i]
|
|
sol_special_wishes+='<td padding=2px>' + getTeamById[t1] + ' </td><td>' + getTeamById[t2] + '</td><td>' + str(global_coeff[t1]*global_coeff[t2]) + '</td> <td>' + game_ko_time[(t1,t2,r,d)] + '</td> <td> </td> '
|
|
sol_special_wishes+='</tr>'
|
|
sol_special_wishes+='<tr><td colspan='+ str(5*nCols)+ '> </td></tr>'
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
earlyMatches = { cc :[] for cc in NAS15 }
|
|
|
|
if not isUEL:
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<h2>Early Match Violations</h2><table class='display table-bordered table-hover'><tbody>"
|
|
for (t1,t2,rd) in x.keys() :
|
|
t1f= getTeamById[t1]
|
|
t2f= getTeamById[t2]
|
|
if getVal(x_time[(t1,t2,rd,getIdByTime["Early"])])>0.9:
|
|
if t_country[t1] in NAS15:
|
|
earlyMatches[t_country[t1]].append((rd[1] , "H", t1))
|
|
if t_country[t2] in NAS15:
|
|
earlyMatches[t_country[t2]].append((rd[1] , "A", t2))
|
|
|
|
print ("<tr><td>Early match with a global coefficient of " + str(quality_of_game(t1,t2)) +' ' + str(quality_of_game_dom(t1,t2)) +' / ' + str(quality_of_game_dom(t2,t1)) + ' </td><td> :' + t1f + " - " +t2f + ' </td></tr>')
|
|
if quality_of_game(t1,t2)>=16 and getVal(x_time[(t1,t2,rd,getIdByTime["Early"])])>0.9:
|
|
sol_special_wishes+='<tr><td>Early match with a global coefficient of ' + str(quality_of_game(t1,t2)) +' </td><td> :' + t1f + " - " +t2f+ ' </td></tr>'
|
|
if (quality_of_game_dom(t1,t2)>=25 or quality_of_game_dom(t2,t1)>=25 ) and getVal(x_time[(t1,t2,rd,getIdByTime["Early"])])>0.9:
|
|
sol_special_wishes+='<tr><td>Early match with a domestic coefficient of ' + str(quality_of_game_dom(t1,t2)) +' / ' + str(quality_of_game_dom(t2,t1)) + '</td><td> :' + t1f + " - " +t2f+ ' </td></tr>'
|
|
|
|
|
|
for d in days:
|
|
if best_global_early[d].value()>0.9:
|
|
sol_special_wishes+='<tr><td>' + getNiceDay[d]+ ' : Best global match early.</td></tr>'
|
|
for c in NAS15:
|
|
if best_dom_early[(c,d)].value()>0.9:
|
|
sol_special_wishes+='<tr><td>' + getNiceDay[d]+ ' : Best domestic match early in '+ c +'.</td></tr>'
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
def g_tms2(dtt):
|
|
return getDateTimeDay[dtt[0]]
|
|
for cc in NAS15:
|
|
earlyMatches[cc]= sorted(earlyMatches[cc], key=g_tms2)
|
|
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<h2>Early Matches in main Markets (home + away)</h2><table class='display table-bordered table-hover'><thead><tr>"
|
|
for c in NAS15:
|
|
sol_special_wishes+='<th colspan=4>' + c+ '</th> '
|
|
sol_special_wishes+="</tr></thead><tbody>"
|
|
nRows= max([len(earlyMatches[c]) for c in NAS15 ])
|
|
for i in range(nRows):
|
|
sol_special_wishes+='<tr >'
|
|
for c in NAS15:
|
|
if i>=len(earlyMatches[c]):
|
|
sol_special_wishes+='<td colspan=3> <td>'
|
|
else:
|
|
d,tp,t =earlyMatches[c][i]
|
|
sol_special_wishes+='<td padding=2px>' + getNiceDay[d] + ' </td><td>' + tp + '</td><td>' + getTeamById[t] + '</td> <td> </td> '
|
|
sol_special_wishes+='</tr>'
|
|
|
|
sol_special_wishes+='<tr>'
|
|
for c in NAS15:
|
|
sol_special_wishes+='<th colspan=4> <b>' + str(len(earlyMatches[c]))+ '</b></th> '
|
|
sol_special_wishes+='</tr>'
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
sol_special_wishes+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_special_wishes+="<h2>Home-/Away patterns and positions</h2><table id='example' class='display table-bordered table-hover'>"
|
|
sol_special_wishes+='<thead><tr><th> </th><th>Position</th><th>MD 1</th><th>MD 2</th><th>MD 3</th><th>MD 4</th><th>MD 5</th><th>MD 6</th></tr></thead><tbody>'
|
|
for cc in sorted([confName[c] for c in confTeams.keys() if len(confTeams[c])<=4]):
|
|
for c in confTeams.keys():
|
|
if confName[c]== cc:
|
|
sol_special_wishes+='<tr><td><b>' + confName[c] + '</b></td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr>'
|
|
for p in positions:
|
|
for t in confTeams[c]:
|
|
if pos[(t,p)].value()>0.9:
|
|
sol_special_wishes+='<tr>'
|
|
sol_special_wishes+='<td>' + getTeamById[t] + '</td> <td>' + str(p) + '</td>'
|
|
for r in rounds:
|
|
ha = "H" if homeInRound[(t,r)].value() > 0.9 else "A"
|
|
sol_special_wishes+='<td>'+ha+'</td>'
|
|
sol_special_wishes+='</tr>'
|
|
sol_special_wishes+='<tr><td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr>'
|
|
# sol_special_wishes+='<tr><td colspan=8> </td></tr>'
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if mathModelName=="UEFA NL" :
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Game sequences</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th colspan=2></th><th colspan=2 >weekdays: Mon, Tue, Wed, Thu</th><th colspan=2 >weekdays: Fri, Sat, Sun</th></tr></thead><tbody>"
|
|
sol_special_wishes+="<tr><th></th><th>Sequence</th><th>H</th><th>A</th><th>H</th><th>A</th></tr></thead><tbody>"
|
|
weekdayCntr={ (t,ha): 0 for t in realteams for ha in ["H","A"] }
|
|
weekendCntr={ (t,ha): 0 for t in realteams for ha in ["H","A"] }
|
|
opp_sp = { (t,r) :"" for t in realteams for r in range(1,7)}
|
|
for (t1,t2,r,d) in currentSolution :
|
|
opp_sp[(t1,r)]=t2
|
|
opp_sp[(t2,r)]=t1
|
|
if getWeekDay[d] in ["Fri" , "Sat", "Sun"]:
|
|
weekendCntr[(t1,"H")]+=1
|
|
weekendCntr[(t2,"A")]+=1
|
|
else:
|
|
weekdayCntr[(t1,"H")]+=1
|
|
weekdayCntr[(t2,"A")]+=1
|
|
|
|
for c in conf_teams.keys() :
|
|
if len(conf_teams[c])<=20:
|
|
sol_special_wishes+="<tr><td colspan=6 ><b>"+ c + "</b> </td></tr>"
|
|
for t in conf_teams[c]:
|
|
seq=""
|
|
if len(conf_teams[c])==4:
|
|
seq="123"
|
|
for r2 in [4,5,6]:
|
|
for r1 in [1,2,3]:
|
|
if opp_sp[(t,r1)]== opp_sp[(t,r2)]:
|
|
seq+=str(r1)
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + seq + "</td><td>" + str(weekdayCntr[t,"H"]) + "</td><td>" + str(weekdayCntr[t,"A"]) + "</td><td>" + str(weekendCntr[t,"H"]) + "</td><td>" + str(weekendCntr[t,"A"]) + "</td></tr>"
|
|
sol_special_wishes+="<tr><td colspan=6 > </td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "minHomeAttractivity" in special_wishes_active:
|
|
sw_type="minHomeAttractivity"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Home Game Attractivities</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team</th><th>Attractivity Score</th><th>Missing Score</th></tr></thead><tbody>"
|
|
for (t) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + str(getTeamById[t]) + "</td><td>" + str("") + "</td><td>" + str(specialWishVio[(sw_type,t)].value()) + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "limit_b2b" in special_wishes_active:
|
|
sw_type="limit_b2b"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Back to Back</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Stadium</th><th>"+_('Round 1')+"</th><th>"+_('Round 2')+"</th></tr></thead><tbody>"
|
|
for (nw,r) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,nw,r)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + str(networkName[nw]) + "</td><td>" + str(r) + "</td><td>" + str(r+1) + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "RecoverBeforeDistantGame" in special_wishes_active :
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Not enough recovery time before a distant game</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team</th><th>Day</th></tr></thead><tbody>"
|
|
for sw_type in ["RecoverBeforeDistantGame"]:
|
|
if sw_type in special_wishes_active:
|
|
for (t,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "RecoverAfterDistantGame" in special_wishes_active or "RecoverAfterDistantGame2" in special_wishes_active :
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Not enough recovery time after a distant game</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team</th><th>Day</th></tr></thead><tbody>"
|
|
for sw_type in ["RecoverAfterDistantGame","RecoverAfterDistantGame2"]:
|
|
if sw_type in special_wishes_active:
|
|
for (t,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "NoSingleDistantGame" in special_wishes_active:
|
|
sw_type="NoSingleDistantGame"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Single distant games</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team</th><th>Day</th></tr></thead><tbody>"
|
|
for (t,d) in sorted(specialWishItems[sw_type]):
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "RestDaysAfterLateGame" in special_wishes_active:
|
|
sw_type="RestDaysAfterLateGame"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Late game not followed buy enough rest days</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team</th><th>Day</th></tr></thead><tbody>"
|
|
for (t,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "3DaysForDistantTeams" in special_wishes_active:
|
|
sw_type="3DaysForDistantTeams"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Not enough rest days when traveling to distant teams</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team 1</th><th>Team 2</th><th>Day</th></tr></thead><tbody>"
|
|
for (t1,t2,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t1,t2,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t1] + "</td><td>" + getTeamById[t2] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "playWeekendsCompletelyHomeOrAway" in special_wishes_active:
|
|
sw_type="playWeekendsCompletelyHomeOrAway"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Teams playing home and away on the same weekend</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team 1</th></th><th>Day</th></tr></thead><tbody>"
|
|
for (t,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
if "alwaysFixedRestDaysWhenPossible" in special_wishes_active:
|
|
sw_type="alwaysFixedRestDaysWhenPossible"
|
|
sol_special_wishes+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_special_wishes+='<div class="ibox"><div class="ibox-title"><h5>Teams not having ' + str(sw_int1[sw_type])+ ' rest days between games</h5> </div><div class="ibox-content">'
|
|
sol_special_wishes+="<table class='display table-bordered table-hover'><thead>"
|
|
sol_special_wishes+="<tr><th>Team 1</th></th><th>Day</th></tr></thead><tbody>"
|
|
for (t,d) in specialWishItems[sw_type]:
|
|
if specialWishVio[(sw_type,t,d)].value()>0.9:
|
|
sol_special_wishes+="<tr><td>" + getTeamById[t] + "</td><td>" + getNiceDay[d] + "</td></tr>"
|
|
sol_special_wishes+='</tbody></table></div></div></div></div>'
|
|
|
|
|
|
if thisSeason.useFeatureBroadcasting:
|
|
print("getTimeOfGame", getTimeOfGame)
|
|
cntr=0
|
|
broadCastFrequency={ (n,t) : 0 for t in teams for n in networkName.keys() }
|
|
sol_broadcasting='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_broadcasting+="<div id='chart_div'></div></div></div></div></div>"
|
|
sol_broadcasting+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_broadcasting+="<table class='display table-bordered table-hover'><thead><tr><th>"+_('Network')+"</th><th>"+_('Day')+"</th><th>"+_('Match')+"</th><th>"+_('Quality')+"</th><th>"+_('Comment')+"</th></tr></thead><tbody>"
|
|
bgcolor="style='background-color:White '"
|
|
# for bw in broadcastingwishes :
|
|
# # if (haw['homeAway']=='Home' and homePat[haw['team_id'], getDayById[haw['day_id']]['round']].value()<0.1) or (haw['homeAway']=='Away' and homePat[haw['team_id'], getDayById[haw['day_id']]['round']].value()>0.9) :
|
|
# bgcolor="style='background-color:PaleGreen '"
|
|
# bgcolor="style='background-color:White '"
|
|
# # if (broadVio[bw['day_id']].value()>0.9) :
|
|
# # bgcolor="style='background-color:#ff9980'"
|
|
# ddd = "SLOTS"
|
|
# if bw.day:
|
|
# ddd=getNiceDay[bw.day.id]
|
|
# sol_broadcasting+='<tr '+ bgcolor+'><td> '+ networkName[bw.network.id] +'</td><td> '+ ddd +'</td><td> '+ str(bw.minGames) +'</td><td> '+ bw.quality +'</td><td> '+ bw.reason +'</td></tr>'
|
|
|
|
for n in networkName.keys():
|
|
sol_broadcasting+='<tr '+ bgcolor+'><td colspan=5>'+ networkName[n]+'</td></tr>'
|
|
for (t1,t2,d,nw) in broadcastingResult :
|
|
if n==nw:
|
|
tm = ""
|
|
if (t1,t2,d) in getTimeOfGame.keys():
|
|
tm = ", " + getTimeById[getTimeOfGame[(t1,t2,d)]]
|
|
sol_broadcasting+='<tr '+ bgcolor+'><td> </td><td>'+getNiceDay[d] + tm+'</td><td> '+ getTeamById[t1] +' - '+ getTeamById[t2] +'</td><td>' + str(attractivity[t1,t2]) +' </td><td> </td></tr>'
|
|
cntr+=attractivity[t1,t2]
|
|
broadCastFrequency[(nw,t1)]+=1
|
|
broadCastFrequency[(nw,t2)]+=1
|
|
# for g in topGames :
|
|
# if x[g[0][0],g[0][1],bw['day_id']].value() >0.9:
|
|
# sol_broadcasting+='<tr '+ bgcolor+'><td>w</td><td colspan=2> '+ getTeamById[g[0][0]] +' - '+ getTeamById[g[0][1]] +'</td><td>' + str(g[1]) +' </td></tr>'
|
|
# if x[g[0][1],g[0][0],bw['day_id']].value() >0.9:
|
|
# sol_broadcasting+='<tr '+ bgcolor+'><td>w</td><td colspan=2> '+ getTeamById[g[0][1]] +' - '+ getTeamById[g[0][0]] +'</td><td>' + str(g[1]) +' </td></tr>'
|
|
sol_broadcasting+='<tr '+ bgcolor+'><td colspan=5> </td></tr>'
|
|
sol_broadcasting+='</tbody></table></div></div></div></div>'
|
|
|
|
sol_broadcasting+='<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>'
|
|
sol_broadcasting+='<script type="text/javascript">'
|
|
sol_broadcasting+="google.charts.load('current', {'packages':['corechart']});"
|
|
sol_broadcasting+='google.charts.setOnLoadCallback(drawChart);'
|
|
sol_broadcasting+="function drawChart() { var options = {'title':'','height':300,chartArea : { left: 50, top:30 },isStacked: true,orientation: 'horizontal', colors: [ '#e6693e','steelblue', 'DarkOrange', 'LightGreen', 'LightCoral', 'SlateGray' ,'Gold'] };"
|
|
sol_broadcasting+='var data = new google.visualization.DataTable();'
|
|
|
|
sol_broadcasting +="var chart = new google.visualization.BarChart(document.getElementById('chart_div'));\n"
|
|
sol_broadcasting +="data.addColumn('string', 'Team');"
|
|
for n in networkName.values():
|
|
sol_broadcasting +="data.addColumn('number', '"+ n+"');\n"
|
|
sol_broadcasting +="data.addRows(["
|
|
for t in teams:
|
|
sol_broadcasting+="['"+getTeamById[t]+"'"
|
|
for n in networkName.keys():
|
|
sol_broadcasting+="," + str(broadCastFrequency[(n,t)])
|
|
sol_broadcasting+="],"
|
|
sol_broadcasting +="]); \nchart.draw(data, options);}</script>"
|
|
|
|
if cntr==0 and len(networkName.keys())==0:
|
|
cntr="0 of 0"
|
|
|
|
# sol_broadcasting+='<div class="col-sm-6 text-center"><label class="label label-success">Bar Chart</label><div id="bar-chart" ></div> </div>'
|
|
|
|
sol_kpis+='Quality of Broadcasting slot assignment__'+ str(cntr)+ '___'
|
|
print ("broadCastFrequency ", broadCastFrequency)
|
|
|
|
cntr=0
|
|
kpi_text="<table>"
|
|
sol_conferences='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-content">'
|
|
sol_conferences+="<table id='example' class='display table-bordered table-hover'><thead><tr><th>"+_('Group')+"</th><th >"+_('Day')+"</th><th align=center>"+_('Min. Number of Games')+" </th><th align=center>"+_('Max. Number of Games')+" </th><th align=center>"+_('Priority')+"</th><th>"+_('Comment')+"</th></tr></thead><tbody>"
|
|
for conf in conferencewishes :
|
|
bgcolor="style='background-color:PaleGreen '"
|
|
if (confVio[conf['id']].value() >0.9) :
|
|
bgcolor="style='background-color:#ff9980'"
|
|
cntr+= int (0.1+confVio[conf['id']].value())
|
|
sol_conferences+='<tr '+ bgcolor+'><td> '+ confName[conf['conference_id']] +'</td><td align=center> '+ getNiceDay[conf['day_id']] +'</td><td align=center> '+ str(conf['minGames']) +'</td><td align=center> '+ str(conf['maxGames']) +'</td><td align=center> '+ str(conf['prio']) +'</td><td> '+ conf['reason'] +'</td></tr>'
|
|
kpi_text += '<tr><td>'+confName[conf['conference_id']] + ': </td><td>' + getNiceDay[conf['day_id']] + '</td></tr>'
|
|
for t1 in confTeams[conf['conference_id']]:
|
|
for t2 in confTeams[conf['conference_id']]:
|
|
for (r,d) in getRoundDaysByDay[conf['day_id']]:
|
|
if (t1,t2,(r,d)) in x.keys() and getVal(x[(t1,t2,(r,d))]) >0.9:
|
|
sol_conferences+='<tr><td></td><td colspan=3>'+ getTeamById[t1] +' - '+ getTeamById[t2] +'</td><td> </td><td> </td></tr>'
|
|
sol_conferences+='</tbody></table></div></div></div></div>'
|
|
kpi_text+="</table>"
|
|
|
|
if cntr==0 and len(conferencewishes)==0:
|
|
cntr="0 of 0"
|
|
|
|
if thisSeason.useFeatureConferences:
|
|
sol_kpis+=_('Violated Group Wishes')+'__'+ str(cntr)+ '__'+ kpi_text+ '___'
|
|
|
|
if mathModelName=="NBA":
|
|
sol_kpis+='Game Repetitions__'+ str(badRepeater_Total_NBA.value())+ '___'
|
|
sol_kpis+='East/West Travel__'+ str(int(eastWestTrip_Total_NBA.value()+0.1))+ '___'
|
|
|
|
kpi_text="<table>"
|
|
for (t1,t2) in realgames:
|
|
if missingGamesVio[(t1,t2)].value() >0.9:
|
|
kpi_text += '<tr><td>'+getTeamById[t1].replace("'","") + '</td><td>-</td><td>' + getTeamById[t2].replace("'","") + '</td></tr>'
|
|
kpi_text+="</table>"
|
|
|
|
sol_kpis+=_('Missing Games')+'__'+ str(int(missingGamesVioTotal.value()/2000000+0.1))+ '__'+ kpi_text + '___'
|
|
|
|
if thisSeason.useFeatureBackToBack:
|
|
b2bvios = [(getTeamById[t],getNiceDay[d], int(0.5+badBackToBack[(t,d)].value())) for t in teams for d in days if (t,d) in badBackToBack.keys() and badBackToBack[(t,d)].value()>0.1 ]
|
|
greenB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==1]
|
|
yellowB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==3]
|
|
redB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==50]
|
|
greyB2B = [ (t1,t2,w) for (t1,t2,w) in b2bvios if w==1000]
|
|
print ( len(greyB2B) , " + ",len(redB2B) , " + ",len(yellowB2B) , " + ",len(greenB2B))
|
|
print (greyB2B+redB2B)
|
|
|
|
sol_kpis+='Back to back__'+ str(len(greyB2B)) + " + " + str(len(redB2B)) + " + " + str(len(yellowB2B)) + " + " + str(len(greenB2B)) + '___'
|
|
|
|
|
|
if sol_kpis!="":
|
|
sol_kpis = sol_kpis[:-3]
|
|
|
|
print (sol_kpis)
|
|
|
|
kpis= [kpit.split("__") for kpit in sol_kpis.split("___")]
|
|
|
|
print (kpis)
|
|
for kpi in kpis:
|
|
sol_quality+='<tr><td>' + kpi[0] + ':</td><td>'+ kpi[1] + '</td></tr>'
|
|
|
|
sol_quality+='</table></div></div></div>'
|
|
|
|
sol_quality+=' <div class="col-lg-3"><div class="ibox"><div class="ibox-title"><h5> '+_('Show travels at')+' </h5></div><div class="ibox-content">'
|
|
sol_quality+='<select style="height: 295px" class="form-control" multiple="" onchange=showPath(this.value)>\n'
|
|
for d in days:
|
|
sol_quality+=' <option value="'+str(d) +'"> '+ getNiceDay[d]+' </option>\n'
|
|
sol_quality+='</select></div></div></div>'
|
|
sol_quality+='<div class="col-lg-4"> <div class="ibox"> <div class="ibox-content"> <div class="google-map" id="map_canvas" style="height: 345px"></div></div> </div> </div>'
|
|
sol_quality+='</div>'
|
|
|
|
|
|
sol_quality+='<div class="row"> <div class="col-lg-12"> '
|
|
sol_quality+='<div class="ibox"><div class="ibox-title"><h5>'+_('Distribution over Weekdays')+'</h5> </div><div class="ibox-content">'
|
|
sol_quality+='<table id="example2" class="display table-bordered table-hover"><thead><tr><th> </th>'
|
|
sol_quality+="<th colspan=2>"+_('Monday')+"</th><th colspan=2>"+_('Tuesday')+"</th><th colspan=2>"+_('Wednesday')+"</th><th colspan=2>"+_('Thursday')+"</th><th colspan=2>"+_('Friday')+"</th><th colspan=2>"+_('Saturday')+"</th><th colspan=2>"+_('Sunday')+"</th> <th> </th> "
|
|
sol_quality+='</tr><tr><th> </th>'
|
|
for wd in weekdays:
|
|
sol_quality+="<th> "+_('Home')+" </th> <th> "+_('Away')+" </th> "
|
|
sol_quality+="<th>"+_('Pref. Home')+"</th> </tr></thead><tbody>"
|
|
for t in realteams :
|
|
goodHomeCntr=0
|
|
goodAllCntr=0
|
|
sol_quality+='<tr><td> ' + getTeamById[t] + ' </td> '
|
|
for wd in weekdays:
|
|
bgcolor = ''
|
|
# if weekdayHomePref[(t,wd)]>= 1 and weekDayDistributionHome[(t, wd)] >= 1 :
|
|
if weekdayHomePref[(t,wd)]>= 1 :
|
|
bgcolor="style='background-color:#1ab394; color:white'"
|
|
# bgcolor="style='background-color:#1ab394'"
|
|
goodHomeCntr+=weekDayDistributionHome[(t, wd)]
|
|
goodAllCntr+=weekDayDistributionHome[(t, wd)]
|
|
sol_quality+='<td align="center" '+bgcolor+'> ' + str(weekDayDistributionHome[(t, wd)]) + ' </td> '
|
|
sol_quality+='<td align="center"> ' + str(weekDayDistributionAway[(t, wd)]) + ' </td> '
|
|
sss=0
|
|
if goodAllCntr>0 :
|
|
sss = int(100*goodHomeCntr/goodAllCntr)
|
|
sol_quality+='<td> <span class="pie">'+str(goodHomeCntr)+'/'+str(goodAllCntr)+'</span> '+ str(sss) +' % </div></td></tr>'
|
|
sol_quality+='</tbody></table> </div> </div> </div> </div>'
|
|
|
|
|
|
firstDay=getDays[1][0]
|
|
for d in getDays[1]:
|
|
if getDateTimeDay[d]<getDateTimeDay[firstDay]:
|
|
d=firstDay
|
|
lastDay=getDays[nRounds][0]
|
|
for d in getDays[nRounds]:
|
|
if getDateTimeDay[d]>getDateTimeDay[lastDay]:
|
|
d=lastDay
|
|
|
|
seasonLength= (getDateTimeDay[lastDay]-getDateTimeDay[firstDay]).days
|
|
avPhaseLength= seasonLength/nPhases
|
|
|
|
realteams_dst = realteams
|
|
|
|
# for c in conferences:
|
|
# print (c)
|
|
|
|
# for (t,d,c) in tripToClusterDaily.keys():
|
|
# print ("+ " , getTeamById[t], getNiceDay[d], " - " , c , type(tripToClusterDaily[(t,d,c)]))
|
|
# if tripToClusterDaily[(t,d,c)].value() >0.3:
|
|
# print ("++ " ,getTeamById[t], getNiceDay[d],c,tripToClusterDaily[(t,d,c)].value() )
|
|
|
|
if thisSeason.groupBased or mathModelName=="Florida State League":
|
|
def t_group(t):
|
|
if t_conference[t]==0:
|
|
return ""
|
|
return t_conference[t].name
|
|
realteams_dst = sorted(realteams, key=t_group)
|
|
|
|
sol_quality+='<div class="row"><div class="col-lg-12"><div class="ibox"> <div class="ibox-title"><h5>'+_('Number of days between encounters of same opponents')+'</h5> </div><div class="ibox-content">\n'
|
|
sol_quality+="<table id='example2' class='table table-header-rotated table-striped table-striped-column '>"
|
|
sol_quality+="<thead ><tr><th> </th>"
|
|
for t2 in realteams_dst :
|
|
sol_quality+='<th class="rotate-45"> <div><span>' + getTeamById[t2] + ' </span></div></th> '
|
|
sol_quality+='</tr></thead><tbody>'
|
|
for t1 in realteams_dst :
|
|
sol_quality+='<tr><td><b> ' + getTeamById[t1] + ' </b> </td> '
|
|
for t2 in realteams_dst :
|
|
games_string =""
|
|
if not t2 in opponents[t1]:
|
|
sol_quality+='<th> </th> '
|
|
else:
|
|
gds = []
|
|
for d in daysSorted:
|
|
for rd in getRoundDaysByDay[d]:
|
|
if getVal(x[(t1,t2,rd)]) + getVal(x[(t2,t1,rd)]) >0.9 and (thisSeason.gamesPerRound=="one day" or rd== getRoundDaysByRound[rd[0]][0]):
|
|
gds.append(d)
|
|
if getVal(x[(t1,t2,rd)]) >0.9:
|
|
games_string +="<tr><td>" + getNiceDay[d] +" </td><td> : " + getTeamById[t1] +" - " + getTeamById[t2] +"</td></tr>"
|
|
else :
|
|
games_string +="<tr><td>" + getNiceDay[d] +" </td><td> : " + getTeamById[t2] +" - " + getTeamById[t1] +"</td></tr>"
|
|
dists =[]
|
|
dist_string = ""
|
|
for i in range(1,len(gds)):
|
|
# print (gds[i-1] , gds[i])
|
|
dt1=getDateTimeDay[gds[i-1]]
|
|
dt2=getDateTimeDay[gds[i]]
|
|
dd=(dt2-dt1).days
|
|
dists.append(dd )
|
|
dist_string += str(dd)+ " "
|
|
pp = 1
|
|
for j in dists:
|
|
pp*=j
|
|
pp = int(100*pow(pp,1.0/max(1,len(dists)) )/avPhaseLength)
|
|
bgcolor="style='background-color:lightyellow;white-space: nowrap; '"
|
|
if pp>85:
|
|
bgcolor="style='background-color:PaleGreen;white-space: nowrap; '"
|
|
if pp<70:
|
|
bgcolor="style='background-color:#ffc966;white-space: nowrap; '"
|
|
if pp<50:
|
|
bgcolor="style='background-color:#ff9980;white-space: nowrap; '"
|
|
if len(dists)==0:
|
|
bgcolor=""
|
|
if dist_string=="" and games_string !="":
|
|
dist_string="x"
|
|
sol_quality+='<td align=center '+ bgcolor +' onMouseover="showInfo(\''+games_string+'\') " onMouseout="hideInfo()" >'+ dist_string+ '</td>'
|
|
sol_quality+='</tr>'
|
|
sol_quality+='<tr><th>'+_('Distance Traveled')+' </th> '
|
|
for t in realteams_dst :
|
|
sol_quality+='<td>'+ scaledDistanceString(totalDistanceTravelled[t]) +'</td> '
|
|
sol_quality+='</tr> '
|
|
sol_quality+='<tr><th>'+_('Home Games')+'</th> '
|
|
for t in realteams_dst :
|
|
sol_quality+='<td>'+ str( int(1*sum([ home[t,d].value()*getDayById[d]['attractivity'] for d in days ]))) +'</td> '
|
|
sol_quality+='</tr> '
|
|
|
|
sol_quality+='</tbody></table></div> </td> </tr> </table> '
|
|
|
|
sol_quality+=' </div></div> </div> <div class="row"> <div class="col-lg-12"><div class="ibox"> <div class="ibox-title"> <h5>'+_('Teams not having enough time to recover between games')+'</h5> </div> <div class="ibox-content">'
|
|
sol_quality+="<table id='example2' class='display table-bordered table-hover'>"
|
|
sol_quality+="<thead><tr><th>"+_('Team')+" </th><th>"+_('First Game')+" </th><th>"+_('Second Game')+" </th>"
|
|
sol_quality+='</tr></thead><tbody>'
|
|
for t1 in realteams :
|
|
for d in days+higherLeagueDayIds :
|
|
playsThatDay = sum([ getVal(home[(t,d)])+getVal(away[(t,d)]) for t in [t1]+higherTeamsOf[t1]])>0.9
|
|
# if playsThatDay :
|
|
# print (getTeamById[t1] , "PLAYS ON ", getNiceDay[d] , [ getNiceDay[d3] for d3 in conflictDays[(t1,d)]] )
|
|
if conflictDays[(t1,d)] and gamesTooClose[(t1,d)].value()>0.9 and playsThatDay:
|
|
sol_quality+='<tr><td><b> ' + getTeamById[t1] + ' </b> </td> '
|
|
sol_quality+='<td> ' + getNiceDay[d] + ' </td> <td> '
|
|
# sol_quality+='<td> ' + str(gamesTooClose[(t,d)].value()) + ' </td> '
|
|
for d2 in conflictDays[(t1,d)]:
|
|
playsThatOtherDay = sum([ getVal(home[(t,d2)])+getVal(away[(t,d2)]) for t in [t1]+higherTeamsOf[t1]])>0.9
|
|
if d2 !=d and playsThatOtherDay:
|
|
# sol_quality+='<td> ' + getNiceDay[d2] + ' </td> '
|
|
sol_quality+= getNiceDay[d2] + ' '
|
|
sol_quality+=' </td> </tr> '
|
|
sol_quality+='</tbody></table> </div></div></div> </div> '
|
|
|
|
sol_quality+=' <div class="row"> <div class="col-lg-12"><div class="ibox"> <div class="ibox-title"> <h5>'+_('Conflicts with international competitions')+'</h5> </div> <div class="ibox-content">'
|
|
sol_quality+="<table id='example2' class='display table-bordered table-hover'>"
|
|
sol_quality+="<thead><tr><th>"+_('Round')+"</th><th>"+_('Date')+"</th><th>"+_('Home')+"</th><th>"+_('Away')+"</th><th>"+_('Competition')+"</th>"
|
|
sol_quality+='</tr></thead><tbody>'
|
|
|
|
for (t1,t2,r,d2) in currentSolution :
|
|
if getTeamById[t1]!='-' and getTeamById[t2]!='-' :
|
|
if (t1,d2) in competitions.keys() :
|
|
# print ('PROBLEM ', t1,t2,r,d2)
|
|
sol_quality+='<tr><td>'+ str(r) +'</td><td>'+ getNiceDay[d2] +'</td><td>'+ getTeamById[t1] +'</td><td>'+ getTeamById[t2] +'</td><td>'+ competitions[(t1,d2)] +'</td></tr>'
|
|
if (t2,d2) in competitions.keys() :
|
|
# print ('PROBLEM ', t1,t2,r,d2)
|
|
sol_quality+='<tr><td>'+ str(r) +'</td><td>'+ getNiceDay[d2] +'</td><td>'+ getTeamById[t1] +'</td><td>'+ getTeamById[t2] +'</td><td>'+ competitions[(t2,d2)] +'</td></tr>'
|
|
sol_quality+='</tbody></table> </div></div></div></div>'
|
|
|
|
# for (t,r) in tooFarViolation.keys():
|
|
# if tooFarViolation[(t,r)].value()>0.9:
|
|
# print ("too far violation " ,r, " ", getTeamById[t])
|
|
|
|
if mathModelName in ["ALPS" ,"ICE Hockey League" , "ICEYSL"]:
|
|
|
|
print ("NICE TRIPS")
|
|
for (tr,d1,d2) in traveling_ICE.keys():
|
|
if traveling_ICE[(tr,d1,d2)].value()>0.9:
|
|
t2,tms = trips_ICE[tr]
|
|
print ("ICE TRIP " , getNiceDay[d1], " ", getTeamById[t2])
|
|
|
|
print ()
|
|
for (t,d1,d2) in toughWeekend_ICE.keys():
|
|
if toughWeekend_ICE[(t,d1,d2)].value()>0.9:
|
|
print ("TOUGH WEEKEND " , getNiceDay[d1], " ", getTeamById[t])
|
|
|
|
print ()
|
|
for (t1,t2,(r,d)) in x.keys():
|
|
if getVal( x[(t1,t2,(r,d))])>0.9 and getWeekDay[d]=="Thu" and distanceById[t1,t2]>250 :
|
|
print ("TOUGH WEEK " , getNiceDay[d], " ", distanceById[t1,t2], " ", getTeamById[t1], " - ", getTeamById[t2])
|
|
|
|
print ()
|
|
for (t1,t2,(r,d)) in toofarForXmas:
|
|
if getVal( x[(t1,t2,(r,d))])>0.9:
|
|
print ("BAD XMAS " , getNiceDay[d], " ", getTeamById[t1], " - ", getTeamById[t2] ," \t " , distanceById[t1,t2] ,"/" , maxDist4[t2]+1 )
|
|
|
|
# for enc in encwishes:
|
|
# if enc['reason']=="Seed Game" :
|
|
# print ("SEED ", 100*prioVal[enc['prio']] * encVio[enc['id']].value())
|
|
# for el in elemEncWishes[enc['id']]:
|
|
# print (el, encVioTooMuch[el].value() , encVioTooLess[el].value() , elemEncWishDays[el] )
|
|
# for d in elemEncWishDays[el]:
|
|
# print (" - ", getNiceDay[d] )
|
|
|
|
|
|
if sharedStadiums :
|
|
stadiumTimeSlotBlockingGames=[]
|
|
getTeamObject = { t.id : t for t in Team.objects.filter(season=thisSeason,active=True)}
|
|
StadiumTimeSlotBlocking.objects.filter(homeTeam_id__in=teams).delete()
|
|
|
|
for (t1,t2,r,d) in currentSolution:
|
|
print ("trying to create " , getTeamById[t1], getTeamById[t2],getNiceDayRaw[d])
|
|
if (t1,d) in usedStadiumTimeSlot.keys():
|
|
ts = stadiumTimeSlotPref[(t1,usedStadiumTimeSlot[(t1,d)]['id'])].stadiumTimeSlot
|
|
newSTSBG = StadiumTimeSlotBlocking(stadiumTimeSlot=ts,
|
|
day=getNiceDayRaw[d], homeTeam=getTeamObject[t1], awayTeam=getTeamObject[t2])
|
|
stadiumTimeSlotBlockingGames.append(newSTSBG)
|
|
print (" ... created ", newSTSBG.day , " \t" , newSTSBG.stadiumTimeSlot.start , " \t" ,newSTSBG.homeTeam.name , " \t" , newSTSBG.awayTeam.name , )
|
|
StadiumTimeSlotBlocking.objects.bulk_create(stadiumTimeSlotBlockingGames)
|
|
|
|
print (usedStadiumTimeSlot.keys())
|
|
|
|
print ("TRIPS")
|
|
for t in teams:
|
|
for d in days:
|
|
for (c,v1,v2,v3,v4) in tripElements[t]:
|
|
if tripToSingleTripElement[(t,d,c)].value() and tripToSingleTripElement[(t,d,c)].value()>0.1:
|
|
print ("- " , getTeamById[t],getNiceDay[d] ," : ",[getTeamById[t2] for t2 in v1] ,"->" ,[getTeamById[t2] for t2 in v2 ] ,"->" ,[getTeamById[t2] for t2 in v3] ,"->" ,[getTeamById[t2] for t2 in v4 ] )
|
|
|
|
getBWish = { bwish.id : bwish for bwish in broadcastingwishes }
|
|
for (b,r) in broadVioTm.keys():
|
|
if broadVioTm[(b,r)].value()>0.9:
|
|
print ("broadVioTm" , b,r , broadVioTm[(b,r)].value() , getBWish[b].network.name)
|
|
|
|
|
|
if lowerBoundFound:
|
|
print ("")
|
|
print("********************************")
|
|
print("* LOWER BOUND : ", lowerBoundFound , " *")
|
|
print("********************************")
|
|
print ("")
|
|
|
|
|
|
thisScenario.lastComputation=datetime.datetime.now()
|
|
thisScenario.sol_solution = sol_solution[:-2]
|
|
thisScenario.sol_prev_solution = thisScenario.sol_solution
|
|
thisScenario.sol_schedule = sol_schedule
|
|
thisScenario.sol_kpis = sol_kpis
|
|
thisScenario.sol_quality = sol_quality
|
|
thisScenario.sol_breaks = sol_breaks
|
|
thisScenario.sol_trips = sol_trips
|
|
thisScenario.sol_pairings = ""
|
|
thisScenario.sol_blockings = ""
|
|
thisScenario.sol_homeaway = ""
|
|
thisScenario.sol_encounters = ""
|
|
thisScenario.sol_broadcasting = sol_broadcasting
|
|
thisScenario.sol_special_wishes = sol_special_wishes
|
|
thisScenario.sol_conferences = sol_conferences
|
|
thisScenario.sol_checked = True
|
|
thisScenario.stopComputation = Scenario.objects.get(id=thisScenario.id).stopComputation
|
|
|
|
if RUN_ENV == 'celery' and task:
|
|
thisScenario.task_id = task.request.id
|
|
else:
|
|
thisScenario.task_id = 0
|
|
thisScenario.save()
|
|
|
|
# create a backup of the scenario
|
|
if not evalRun:
|
|
savingtime = datetime.datetime.now().replace(microsecond=0)
|
|
backup = ScenarioBackup.objects.create(season=thisSeason, name=thisScenario.name, saved_at=savingtime, objective=last_objective)
|
|
fs = FileSystemStorage('data/')
|
|
directory = "save_point/{}/{}/".format(thisLeague.id,thisSeason.id)
|
|
os.makedirs("data/"+directory, exist_ok=True)
|
|
filename = "{}.json".format(backup.id)
|
|
with fs.open('{}/{}'.format(directory,filename), 'w') as f:
|
|
f.write(serialize_scenario(thisScenario))
|
|
|
|
if RUN_ENV == 'celery':
|
|
dup2(orig_std_out, 1)
|
|
close(orig_std_out)
|
|
f.close()
|
|
print({'timestamp':time.time(),'objective': last_objective, "user ": user_name, "league ": str(thisLeague)})
|
|
else:
|
|
print("Success!")
|
|
|
|
# %% |