1937 lines
73 KiB
Python
Executable File
1937 lines
73 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 scheduler.models import *
|
|
import operator
|
|
from scheduler.solver.functions import *
|
|
from common.functions import distanceInKmByGPS
|
|
import pandas as pd
|
|
import numpy as np
|
|
from django.db.models import Count, F, Value
|
|
from pulp import *
|
|
|
|
|
|
def makeIntVar(v):
|
|
if type(v) != int:
|
|
v.cat = 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()
|
|
|
|
|
|
user_is_staff = True
|
|
runMode = 'New'
|
|
localsearch_time = 0
|
|
solver = '?'
|
|
|
|
s2 = 3
|
|
thisScenario = Scenario.objects.get(id=s2)
|
|
thisSeason = thisScenario.season
|
|
thisLeague = thisSeason.league
|
|
|
|
|
|
mathModelName = thisLeague.name
|
|
if thisSeason.optimizationParameters != "":
|
|
mathModelName = thisSeason.optimizationParameters
|
|
|
|
# %%
|
|
|
|
|
|
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}
|
|
|
|
for t1 in teams:
|
|
for t2 in teams:
|
|
if t1 != t2:
|
|
gameCntr[(t1, t2)] += nPhases/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)
|
|
|
|
# %%
|
|
|
|
gmClusters = range(1, nTeams+2)
|
|
|
|
if nPhases > 0 and not thisSeason.useFeatureOpponentMatrix and not specialGameControl:
|
|
gmClusters = range(1, 2)
|
|
|
|
print("gmClusters", gmClusters)
|
|
|
|
|
|
gameClusterTeams = {c: [t for t in teams] 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])
|
|
|
|
# %%
|
|
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)
|
|
|
|
getPhaseOfRound = {r: min(nPhases-1, int((r-1)/nRoundsPerPhase))
|
|
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}
|
|
|
|
|
|
toTime = False
|
|
|
|
|
|
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
|
|
|
|
|
|
# %%
|
|
basicTeams = teams
|
|
basicGames = [(t1, t2)
|
|
for (t1, t2) in games if t1 in basicTeams and t2 in basicTeams]
|
|
|
|
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])
|
|
|
|
|
|
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}
|
|
|
|
excessGames = {rd: -roundDaysMax[rd] for rd in roundDays}
|
|
deficientGames = {rd: roundDaysMin[rd] for rd in roundDays}
|
|
|
|
excessGames = {rd: max(0, excessGames[rd]) for rd in roundDays}
|
|
deficientGames = {rd: max(0, deficientGames[rd]) for rd in roundDays}
|
|
|
|
# %%
|
|
|
|
|
|
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)
|
|
|
|
|
|
onlyEarlyDays = []
|
|
onlyLateDays = []
|
|
|
|
|
|
alwaysConsiderAllGames = not mathModelName in [
|
|
"Florida State League", "UEFA NL"]
|
|
|
|
|
|
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])
|
|
|
|
gameAttractivity = {(t1, t2): attractivity[t1, t2]
|
|
for (t1, t2) in games if t1 < t2}
|
|
|
|
|
|
sorted_gameAttractivity = sorted(
|
|
gameAttractivity.items(), key=operator.itemgetter(1))
|
|
|
|
nGames = len(games)
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
|
|
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:
|
|
use2BreakPatterns = True
|
|
|
|
half_symmetry_offset = 0 if thisSeason.symmetry or use2BreakPatterns or not thisSeason.startWithBreakAllowed or not thisSeason.endWithBreakAllowed else 1
|
|
|
|
|
|
prev_mirror_round = {r: 0 if r <= nRounds1 else r -
|
|
nRounds1+half_symmetry_offset for r in basicRounds}
|
|
|
|
|
|
for r in basicRounds:
|
|
if r > nRounds1 and int((r-1)/nRounds1) == int((prev_mirror_round[r]-1)/nRounds1):
|
|
prev_mirror_round[r] = int(
|
|
(r-1)/nRounds1-1)*nRounds1 + half_symmetry_offset+1-prev_mirror_round[r] % nRounds1
|
|
|
|
|
|
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}
|
|
|
|
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]]
|
|
|
|
available_days = {(t, d): 1 for t in teams for d in days}
|
|
|
|
|
|
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}
|
|
|
|
# %%
|
|
|
|
model2 = LpProblem(
|
|
"League_Scheduling_Model_--_Schedule_Games_"+str(thisScenario.id), LpMinimize)
|
|
|
|
|
|
nextDay = {d: -1 for d in days}
|
|
previousDay = {d: -1 for d in days}
|
|
|
|
# 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]
|
|
|
|
|
|
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 (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}
|
|
|
|
# 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}
|
|
|
|
for (t1, t2) in games:
|
|
for rd in roundDays:
|
|
if x[(t1, t2, rd)] == 1:
|
|
if not evalRun:
|
|
x[(t1, t2, rd)] = LpVariable('x_'+str(t1)+'_'+str(t2)+'_' +
|
|
str(rd[0])+'_'+str(rd[1]), lowBound=0, upBound=1, cat=LpContinuous)
|
|
cntr += 1
|
|
else:
|
|
cntr += len(roundDays)
|
|
|
|
for r in rounds:
|
|
x_round[(t1, t2, r)] = LpVariable('x_round_'+str(t1)+'_' +
|
|
str(t2)+'_'+str(r), lowBound=0, upBound=1, cat=LpContinuous)
|
|
model2 += x_round[(t1, t2, r)] == sum([x[(t1, t2, rd)]
|
|
for rd in getRoundDaysByRound[r]]), f'game_{t1}_{t2}_sum_of_days_equals_round_{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
|
|
|
|
|
|
|
|
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)], f"symmetric_{r}_{prev_round}"
|
|
|
|
|
|
homeInRound = {(t1, r): LpVariable('homeInRound_'+str(t1)+'_'+str(r),
|
|
lowBound=0, upBound=1, cat=LpContinuous) for t1 in teams for r in rounds}
|
|
awayInRound = {(t1, r): LpVariable('awayInRound_'+str(t1)+'_'+str(r),
|
|
lowBound=0, upBound=1, cat=LpContinuous) for t1 in teams for r in rounds}
|
|
gameInBasicRound = {(t1, t2, r): LpVariable('gameInBasicRound_'+str(t1)+'_'+str(t2)+'_'+str(r), lowBound=0,
|
|
upBound=defaultGameRepetions, cat=LpContinuous) for (t1, t2) in games for r in basicRounds}
|
|
homeInBasicRound = {(t1, r): LpVariable('homeInBasicRound_'+str(t1)+'_'+str(
|
|
r), lowBound=0, cat=LpContinuous) for t1 in teams for r in basicRounds}
|
|
awayInBasicRound = {(t1, r): LpVariable('awayInBasicRound_'+str(t1)+'_'+str(
|
|
r), lowBound=0, cat=LpContinuous) for t1 in teams for r in basicRounds}
|
|
break3InRound = {(t1, r): LpVariable('break3InRound_'+str(t1)+'_'+str(r),
|
|
lowBound=0, cat=LpContinuous) for t1 in teams for r in rounds}
|
|
# breakInRound= {(t1,r) : LpVariable('breakInRound_'+str(t1)+'_'+str(r), lowBound = 0, upBound = 1, cat = LpContinuous) for t1 in teams for r in rounds}
|
|
# breaksTotal = LpVariable('breaksTotal', lowBound = 0, cat = LpContinuous)
|
|
pairingVio = {(pair['id'], d): LpVariable('pairingVio_'+str(pair['id'])+'_' +
|
|
str(d), lowBound=0, cat=LpContinuous) for pair in pairings for d in days}
|
|
derbyMissing = {d: LpVariable(
|
|
'derbyMissing_'+str(d), lowBound=0, cat=LpContinuous) for d in days}
|
|
|
|
breakVio = {(br['id'], t): LpVariable('breakVio_' + str(br['id'])+'_' +
|
|
str(t), lowBound=0, cat=LpContinuous) for br in breaks for t in teams}
|
|
blockingVio = {bl['id']: LpVariable(
|
|
'blockingVio_' + str(bl['id']), lowBound=0, cat=LpContinuous) for bl in blockings}
|
|
# blockingVioTotal = LpVariable('blockingVioTotal', lowBound = 0, cat = LpContinuous)
|
|
|
|
hawVio = {haw['id']: LpVariable(
|
|
'hawVio' + str(haw['id']), lowBound=0, cat=LpContinuous) for haw in hawishes}
|
|
HawVioTooLess = {el: LpVariable('havviotooless_' + str(el), lowBound=0, cat=LpContinuous)
|
|
for haw in hawishes for el in elemHaWishes[haw['id']]}
|
|
HawVioTooMuch = {el: LpVariable('havviotoomuch_' + str(el), lowBound=0, cat=LpContinuous)
|
|
for haw in hawishes for el in elemHaWishes[haw['id']]}
|
|
# HawVioTotal = LpVariable('HawVioTotal', lowBound = 0, cat = LpContinuous)
|
|
encVio = {enc['id']: LpVariable(
|
|
'encVio' + str(enc['id']), lowBound=0, cat=LpContinuous) for enc in encwishes}
|
|
encVioTooLess = {el: LpVariable('encViotooless' + str(enc['id'])+"_"+str(
|
|
el), lowBound=0, cat=LpContinuous) for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
encVioTooMuch = {el: LpVariable('encViotoomuch' + str(enc['id'])+"_"+str(
|
|
el), lowBound=0, cat=LpContinuous) for enc in encwishes for el in elemEncWishes[enc['id']]}
|
|
# encVioTotal = LpVariable('encVioTotal', lowBound = 0, cat = LpContinuous)
|
|
# broadVio = { d : LpVariable('broadVio'+ str(d) , lowBound = 0, cat = LpContinuous) for d in days}
|
|
broadVioTm = {(b.id, r): LpVariable('broadVioTm_' + str(b.id) + "_" + str(r),
|
|
lowBound=0, cat=LpContinuous) for b in broadcastingwishes for r in rounds}
|
|
gamesTooClose2 = {(t, r): LpVariable('gamesTooClose2_' + str(t) + '_' +
|
|
str(r), lowBound=0, cat=LpContinuous) for t in teams for r in rounds}
|
|
missingGamesVio = {(t1, t2): LpVariable('missingGamesVio_' + str(t1) +
|
|
'_'+str(t2), lowBound=0, cat=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] for r in getRealRounds[br] for rd in getRoundDaysByRound[r]) for br in basicRounds}
|
|
|
|
for t in realteams:
|
|
for d in days:
|
|
away[t, d] = lpSum([x[(t2, t, rd)] for t2 in opponents[t] for rd in getRoundDaysByDay[d]]) or LpVariable(
|
|
'away'+str(t)+'_'+str(d), lowBound=0, upBound=0, cat=LpContinuous)
|
|
home[t, d] = lpSum([x[(t, t2, rd)] for t2 in opponents[t] for rd in getRoundDaysByDay[d]]) or LpVariable(
|
|
'home'+str(t)+'_'+str(d), lowBound=0, upBound=0, cat=LpContinuous)
|
|
|
|
|
|
for t in realteams:
|
|
for r in rounds:
|
|
if thisSeason.gamesPerRound == "one day":
|
|
model2 += homeInRound[(t, r)] == lpSum([x[(t, t2, rd)]
|
|
for t2 in opponents[t] for rd in getRoundDaysByRound[r]]), f'team_{t}_home_in_round_{r}'
|
|
model2 += awayInRound[(t, r)] == lpSum([x[(t2, t, rd)]
|
|
for t2 in opponents[t] for rd in getRoundDaysByRound[r]]), f'team_{t}_away_in_round_{r}'
|
|
|
|
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)], f'team_{t}_home_break_in_round_{r}'
|
|
# model2 += break3InRound[(t, r)] + 2 >= awayInRound[(t, r-2)] + \
|
|
# awayInRound[(t, r-1)]+awayInRound[(t, r)], f'team_{t}_away_break_in_round_{r}'
|
|
|
|
|
|
|
|
|
|
breakVioBalance = {t: LpVariable(
|
|
'breakVioBalance_'+str(t), lowBound=0, cat=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']]
|
|
|
|
# for t in realteams:
|
|
# for bl in breaks:
|
|
# bl_id = bl['id']
|
|
# model2 += breakVio[(bl['id'], t)] + 1 >= homeInRound[t,
|
|
# bl['round1']] + homeInRound[t, bl['round2']], f'breakvio_home_{bl_id}_for_{t}'
|
|
# model2 += breakVio[(bl['id'], t)] + 1 >= awayInRound[t,
|
|
# bl['round1']] + awayInRound[t, bl['round2']], f'breakvio_away_{bl_id}_for_{t}'
|
|
|
|
getDays[0] = []
|
|
|
|
|
|
use_currentSolution = False
|
|
|
|
currentGameCntr = {(t1, t2): 0 for t1 in teams for t2 in teams}
|
|
|
|
|
|
# if use_currentSolution and len(currentSolution) !=len(fixedGames):
|
|
|
|
teamGameCntr = {(t, r): 0 for t in teams for r in rounds}
|
|
|
|
|
|
# print ("days " , days)
|
|
for d in days:
|
|
minG = sum([roundDaysMin[rd] - deficientGames[rd]
|
|
for rd in getRoundDaysByDay[d]])
|
|
maxG = sum([roundDaysMax[rd] + excessGames[rd]
|
|
for rd in getRoundDaysByDay[d]])
|
|
model2 += lpSum([home[(t, d)] for t in realteams]) <= maxG, f'max_games_on_day_{d}'
|
|
|
|
# if len(getRoundDaysByDay[d]) > 1:
|
|
# for rd in getRoundDaysByDay[d]:
|
|
# 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, f'one_game_in_round_{r}_for_{t1}'
|
|
|
|
# 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)], f'let_{t1}_{t2}_play_gameCntr_times'
|
|
|
|
missingGamesVio[(t1, t2)].upBound = max(
|
|
0, gameCntr[(t1, t2)]+undirectedGameCntr[(t1, t2)] - currentGameCntr[(t1, t2)])
|
|
|
|
|
|
# %%
|
|
|
|
# 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])
|
|
missingGamesVioTotal = lpSum(
|
|
[2000000 * missingGamesVio[(t1, t2)] for (t1, t2) in realgames])
|
|
|
|
standardObjectives = 0 \
|
|
+ missingGamesVioTotal\
|
|
# + gew['Breaks']*breakVioTotal \
|
|
# + gew['Breaks']*2*break3VioTotal \
|
|
|
|
model2 += standardObjectives
|
|
|
|
|
|
for v in model2.variables():
|
|
v.cat = LpInteger
|
|
|
|
|
|
with open ("model2.txt", "w") as f:
|
|
f.write(model2.__repr__())
|
|
|
|
|
|
model2.solve(XPRESS(msg=1))
|
|
|
|
# print(model2.sol_status)
|
|
# for var in model2.variables():
|
|
# if var.value() and var.value() > 0:
|
|
# print(var,var.value())
|
|
|
|
|
|
|
|
# %%
|
|
|
|
sum([1 for k in x_round.keys() if type(x_round[k]) != int and x_round[k].value() > 0])
|
|
|
|
games_dict = defaultdict(lambda:[])
|
|
for key in x_round.keys():
|
|
if type(x_round[key]) != int and x_round[key].value() > 0:
|
|
games_dict[key[2]].append((key[0],key[1]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# %%
|
|
exit()
|
|
|
|
if not evalRun:
|
|
for (t1, t2) in realgames:
|
|
# every pair plays each other in each phase once
|
|
for p in phases:
|
|
# phase violation in last phase possible if it contained more rounds than necessary
|
|
if p < len(phases)-1 or True:
|
|
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 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)] = LpVariable(
|
|
'hawOneVio_'+str(haw['id'])+"_"+rtname, cat=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)] = LpVariable(
|
|
'hawForOneViolated_'+str(haw['id'])+"_"+rtname+"_"+str(fd), cat=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])] = LpVariable(
|
|
'encForOneNotViolated_'+str(enc['id'])+"_"+str(ed[0]), cat=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")
|
|
|
|
|
|
# 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])
|
|
# 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"])
|
|
# 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])
|
|
# 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"])
|
|
derbiesMissingTotal = lpSum([30 * derbyMissing[d] for d in days])
|
|
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])
|
|
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"
|
|
|
|
# tvkitproblem = {}
|
|
move2 = {}
|
|
newtrip2 = {}
|
|
|
|
|
|
standardObjectives = 1+gew['Home-/Away']*HawVioTotal\
|
|
+ gew['Home-/Away']*3*unpreferredTotal \
|
|
+ gew['Pairings']*pairingVioTotal \
|
|
+ gew['Blockings']*blockingVioTotal \
|
|
+ gew['Traveling']*travelVioTotal \
|
|
+ gew['Breaks']*breakVioTotal \
|
|
+ gew['Breaks']*2*break3VioTotal \
|
|
+ gew['Breaks']*1*breakImbalanceTotal \
|
|
+ 5*gew['Encounters']*encVioTotal \
|
|
+ 5*gew['Encounters']*seedVioTotal \
|
|
+ gew['Broadcasting']*broadVioTotal \
|
|
+ gew['Derbies']*derbiesMissingTotal \
|
|
+ 1.0*tooManyTop4InRowTotal\
|
|
+ missingGamesVioTotal\
|
|
+ oldScenGamesTotal\
|
|
- 0.01*totalAttendance
|
|
|
|
|
|
model2 += standardObjectives
|
|
|
|
# %%
|
|
script = thisSeason.optimizationScript
|
|
if script == '':
|
|
if useBasicGames:
|
|
script += "HEURISTIC\n"
|
|
script += "GAME;1-"+str(nRounds)+";0.1;200\n"
|
|
if thisSeason.groupBased:
|
|
for c in allConferences:
|
|
if not c.regional and c.teams.count() <= 12:
|
|
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 = script.replace('\r', '')
|
|
print("script")
|
|
print(script)
|
|
optSteps = [st.split(';') for st in script.split("\n")]
|
|
print(optSteps)
|
|
|
|
# %%
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
|
|
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 st[0] == "HOMEAWAY":
|
|
for t in teams:
|
|
for r in newRounds:
|
|
homeInRound[(t, r)].cat = LpInteger
|
|
|
|
if st[0] == "BASICGAME":
|
|
for (t1, t2) in games:
|
|
for r in newRounds:
|
|
gameInBasicRound[(t1, t2, r)].cat = 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)])
|
|
|
|
print('########################')
|
|
print('# SOLVING MODEL '+optTarget+' FOR ROUNDS ' + newRoundsString +
|
|
' USING GAP ' + str(optstepgap) + ' and MAXTIME ' + str(optsteptime) + ' #')
|
|
print('########################')
|
|
|
|
# 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))
|
|
|
|
# if model2.status < 0:
|
|
# print("Status: ", model2.status)
|
|
|
|
# if not lowerBoundFound:
|
|
# lowerBoundFound = value(model2.objective)
|
|
|
|
# cntr_rnd = 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
|
|
|
|
# if st[0] in ["GAME", "GAMES"]:
|
|
# feedback = "Optimize games...."
|
|
# missing_imp = []
|
|
|
|
# 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)
|
|
|
|
# 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 = LpContinuous
|
|
# gameInBasicRound[(t1, t2, r)].lowBound = 0
|
|
|
|
# for t in realteams:
|
|
# for r in newRounds:
|
|
# homeInRound[(t, r)].cat = LpContinuous
|
|
# for t2 in opponents[t]:
|
|
# for rd in getRoundDaysByRound[r]:
|
|
# if (t, t2) in games and getVal(x[(t, t2, rd)]) > 0.9:
|
|
# 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]
|
|
|
|
|
|
# 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)])
|
|
|
|
# print('Solved Again')
|
|
# print('NOW REOPT')
|
|
|
|
# # %%
|
|
|
|
# %%
|