research/machine_learning/scripts/qubo/qubo_from_model1_notebook.py
2024-01-31 21:41:29 +01:00

1673 lines
59 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}
comptime,gap = 500, 0
# def optimize_model1(comptime,gap):
TSP=[]
numPatterns= 2*nRounds1
numBreaks= nTeams/2
patternRange=[p for p in range(1,numPatterns+1)]
patterns={}
# print (numPatterns, " :"+numPatterns)
# for t in teams:
# print (t, " :", strength[t])
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=[]
# IMPORTANT: THIS SHOULD BE INCLUDED AGAIN: WHY RESTRICTING SO HARD?
# -> because it insures feasibility of chosen pattern set
onlyUsePrimaryPatternSet=nTeams<20
if onlyUsePrimaryPatternSet:
for p in patternRange:
if thisSeason.symmetry:
if (p % 4 == 0 and p<2*nRounds1-4) or p==2*nRounds1:
forbiddenPatterns.append(p-1)
forbiddenPatterns.append(p)
else:
if (p % 4 == 0 ) :
forbiddenPatterns.append(p-1)
forbiddenPatterns.append(p)
nBreaksOfPat ={ p : 3 for p in patternRange }
nBreaksOfPat[1]=0
nBreaksOfPat[2]=0
print ("forbiddenPatterns" , forbiddenPatterns)
# print ("patternRange" , patternRange)
if use2BreakPatterns :
p_cntr=numPatterns
for b1 in rounds1:
for b2 in rounds1:
if b1+4<=b2 and (b1-b2)%2==0 and b1>1 and b2-b1<nTeams-3:
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)
nBreaksOfPat[p_cntr-1]=4
nBreaksOfPat[p_cntr]=4
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]]
if thisSeason.forbidDoubleBreaks and thisSeason.symmetry:
forbiddenStarterPatterns+= [ p for p in patternRange if patterns[p,2]==patterns[p,3]]
forbiddenEndPatterns += [ p for p in patternRange if patterns[p,nRounds1-2]==patterns[p,nRounds1-1]]
if mathModelName in ["Lega Basket Seria A"] and True :
forbiddenPatterns = [ p for p in patternRange if patterns[p,3]==patterns[p,4] or patterns[p,nRounds1-3]==patterns[p,nRounds1-2] ]
for p in patternRange:
if balanceBreaks and p in [1,2]:
forbiddenPatterns.append(p)
# take care that season halves can be glued together
if (thisSeason.maxTourLength==2 and patterns[p,1]!=patterns[p,nRounds1]
and (patterns[p,1]==patterns[p,2] or patterns[p,nRounds1-1]==patterns[p,nRounds1])):
forbiddenPatterns.append(p)
if haSymmetric:
forbiddenPatterns+=forbiddenStarterPatterns+forbiddenEndPatterns
print ("forbiddenPatterns ",forbiddenPatterns)
print ("patternRange ",patternRange)
for p in patternRange:
nHome = sum ([ patterns[p,d] for d in rounds1 ])
# print ("+++" ,p, nHome , nHome < nRounds1/2-1 , nHome > nRounds1/2+1 , thisScenario.usePhases)
if (nHome < nRounds1/2-1 or nHome > nRounds1/2+1) and thisScenario.usePhases:
forbiddenPatterns.append(p)
# print ("\nbad pattern :" , p)
print ("\nforbidding :")
for p in set(forbiddenPatterns):
for d in rounds1:
print (patterns[p,d],end="")
print ("removing ", p)
# Why should we only really remove patterns with 2 breaks?
if len(patternRange)>2*len(teams)-2 or mathModelName in ["Lega Basket Seria A"]:
patternRange.remove(p)
# take always care of proper start and end
patternRange = [p for p in patternRange if p not in forbiddenStarterPatterns+forbiddenEndPatterns ]
for p in patternRange:
print ( "\n",100+p , " :" ,end="")
for d in rounds1:
print (patterns[p,d],end="")
print (" " ,p not in forbiddenPatterns ,end="")
# if (p % 4 == 0 and p<nRounds-4) or p==nRounds:
# print ("##")
print ("forbiddenPatterns" , forbiddenPatterns)
patternCircle =[]
for p in range(1,len(patternRange)-1):
i = 2*p
if i >= len(patternRange):
i-=len(patternRange)
if i >0:
i+=1
patternCircle.append(patternRange[i])
patternCircle.append(2)
neighborPattern={}
for i in range(1,len(patternCircle)):
neighborPattern[patternCircle[i-1]]=patternCircle[i]
neighborPattern[patternCircle[-1]] =patternCircle[0]
# %%
model = LpProblem("League_Scheduling_Model_-_Assign_Patterns_"+str(thisScenario.id), LpMinimize)
# usePattern={(p,ph) : LpVariable('usePat_'+str(p) + '_' + str(ph), lowBound = 0, upBound = 10, cat = LpInteger) for p in patternRange for ph in preplan_phases}
assignPattern={(p,t1,ph) : LpVariable('assignPattern_'+str(t1)+'_'+str(p)+'_'+str(ph), lowBound = 0, upBound = 1, cat = LpInteger) for p in patternRange for t1 in basicTeams for ph in preplan_phases}
# blockingVio1 = LpVariable('blockingVio1', lowBound = 0, cat = LpContinuous)
# HawVio1TooLess = { el : LpVariable('havvio1tooless_'+ str(haw['id'])+"_"+str(el) , lowBound = 0, cat = LpContinuous) for haw in hawishes for el in elemHaWishes[haw['id']]}
# HawVio1TooMuch = { el : LpVariable('havvio1toomuch_'+ str(haw['id'])+"_"+str(el) , lowBound = 0, cat = LpContinuous) for haw in hawishes for el in elemHaWishes[haw['id']]}
# HawVio1 = { haw['id'] : LpVariable('havvio_'+ str(haw['id']) , lowBound = 0, cat = LpContinuous) for haw in hawishes}
# HawVio1Total = LpVariable('HawVio1Total', lowBound = 0, cat = LpContinuous)
# encVio1 = { el : LpVariable('encVio1'+ str(enc['id']) + '_'+ str(el) , lowBound = 0, cat = LpContinuous) for enc in encwishes for el in elemEncWishes[enc['id']]}
# encVio1Total = LpVariable('encVio1Total', lowBound = 0, cat = LpContinuous)
# totalDistanceSaved1 = LpVariable('totalDistanceSaved1', lowBound = 0, cat = LpContinuous)
# tooManyHomesInStadium1= {(stadium,r) : LpVariable('tooManyHomesInStadium_'+str(stadium)+'_'+str(r), lowBound = 0, cat = LpContinuous) for stadium in stadiums for r in basicRounds}
# pairingVio1= {(pair['id'],r) : LpVariable('pairingVio1_'+str(pair['id'])+'_'+str(r), lowBound = 0, cat = LpContinuous) for pair in pairings for r in basicRounds}
# gamesTooClose1 = { (t1,t2) : LpVariable('gamesTooClose1_'+ str(t1) +'_'+ str(t2) , lowBound = 0, cat = LpContinuous) for (t1,t2) in games }
print ("basicRounds",basicRounds)
print ("useFullModel1",useFullModel1)
complementary_pattern = { p : p-1 if p%2==0 else p+1 for p in patternRange}
print ("phases", phases)
print ("preplan_phases", preplan_phases)
print ("patternRange",patternRange)
for ph in preplan_phases:
if ph==0 or half_symmetry_offset==0 :
for p in patternRange :
# model+= usePattern[(p,ph)]== sum([ assignPattern[p,t,ph] for t in basicTeams]), f"usePattern_{p}_{ph}"
# if p%2==0:
# model+= usePattern[(p,ph)]==usePattern[complementary_pattern[p],ph], f"complementaries_{p}_{complementary_pattern[p]}"
# print ("complementaries " , p, complementary_pattern[p])
# every pattern at most one team in each game cluster
for c in gameClusters:
# print (c, gameClusterTeams[c] , len(patternRange))
model += lpSum( assignPattern[(p,t,ph)] for t in basicTeams if t in gameClusterTeams[c] )<=1 , "one_team_for_pattern_%s_%s_%s" %(p,c,ph)
# every team one pattern
# for t in basicTeams:
# print ("one_pattern_for_",ph,t)
# print ("one_pattern_for_",t, lpSum( assignPattern[(p,t,ph)] for p in patternRange))
# model += lpSum( assignPattern[(p,t,ph)] for p in patternRange)==1 , "one_pattern_for_each_team_%s_%s"%(t,ph)
x12 ={}
if useFullModel1 :
x11={(t1,t2,d) : LpVariable('x11_'+str(t1)+'_'+str(t2)+'_'+str(d), lowBound = 0, upBound = 1, cat = LpInteger) for (t1,t2) in basicGames for d in basicRounds if (d <= nRounds1 or (not thisSeason.symmetry and not haSymmetric))}
tripToCluster1 = {}
away_in_cluster1 = {}
for r in basicRounds:
for (t1,t2) in games:
if t1 in basicTeams and t2 in basicTeams:
if r <= nRounds1 or (not thisSeason.symmetry and not haSymmetric):
x12[(t1,t2,r)] = x11[(t1,t2,r)]
else:
x12[(t1,t2,r)] = x12[(t2,t1,prev_mirror_round[r])]
for (t1,t2) in basicGames:
model += lpSum( x12[(t1,t2,r)] for r in basicRounds) >= gameCntr[(t1,t2)], f"gameCntr_{t1}_{t2}"
# teams meet at most once in each phase
# print (t1,t2,not haSymmetric , thisScenario.usePhases , (t2,t1) in games)
if thisScenario.usePhases and (t2,t1) in basicGames and t1<t2:
for ph in phases:
model += lpSum( [x12[(t1,t2,r)] + x12[(t2,t1,r)] for r in getBasicRoundsOfPhase[ph]]) <=1, f"meet_in_phase_{ph}_once_{t1}_{t2}"
# print (t1,t2, "only once in", getBasicRoundsOfPhase[ph])
cntr=0
# else:
# for p in patternRange:
# print (p)
# if p%2==0:
# for c in gameClusters:
# for t in basicTeams :
# if t in gameClusterTeams[c]+faketeams :
# print (p,t ,ph, (p,t,ph) in assignPattern.keys() ,(p-1,t,ph) in assignPattern.keys() )
# model.solve(GUROBI(MIPGap=0.0, TimeLimit=10))
# for pt in assignPattern.keys():
# if assignPattern[pt].value()>0:
# print (pt, assignPattern[pt].value())
# # todo2 raus
# model += lpSum( x12[(t1,t2,r)] for r in basicRounds for (t1,t2) in games ) >=304
# model.writeLP("LPfile.txt")
# model.solve(GUROBI(MIPGap=0.0, TimeLimit=10))
# print (basicTeams)
# print (patternRange)
print (basicTeams)
print (basicRounds)
homePat={}
awayPat={}
for t in basicTeams:
for d in sorted(basicRounds):
# model+=homePat[t,d]+awayPat[t,d]<=1
if usePatterns and (half_symmetry_offset==0 or d<=nRounds1) and getPhaseOfBasicRound[d] in preplan_phases:
# if usePatterns and (half_symmetry_offset==0 or d<=nRounds1) and getPhaseOfBasicRound[d] in [0]:
homePat[t,d] = lpSum(assignPattern[(p,t,getPhaseOfBasicRound[d])] * patterns[p,d-getPhaseOfBasicRound[d]*nRounds1] for p in patternRange)
else:
homePat[t,d] = LpVariable('homePat_'+str(t) + '_' + str(d), lowBound = 0, upBound = 1, cat = LpInteger)
awayPat[t,d] = 1- homePat[t,d]
if useFullModel1:
model+=homePat[t,d] == lpSum( [ x12[(t,t2,d)] for t2 in basicTeams if gameCntr[(t,t2)]+undirectedGameCntr[(t,t2)]>0] ), f"homeGame_{t}_{d}"
# model+=awayPat[t,d] == lpSum( [ x12[(t2,t,d)] for t2 in basicTeams if gameCntr[(t2,t)]>0] )
print ("teams constraints built")
if useFullModel1:
# as many teams playing home as away in every round
for r in basicRounds:
if getPhaseOfBasicRound[r]==0 or not thisSeason.symmetry :
realBasicTeams = [ t for t in basicTeams if t in realteams]
# print (basicTeams , realBasicTeams , " play at least ", int(0.5*len(realBasicTeams) ) , " home games per basicround", basicRounds )
model += lpSum( homePat[t,r] for t in realBasicTeams )>= int(0.5*len(realBasicTeams) )
for t1 in basicTeams:
# play at most one game per round
model += lpSum( x12[(t1,t2,r)]+x12[(t2,t1,r)] for t2 in basicTeams if (t1,t2) in games )<= 1
# couple to home pattern
# print ( "couple to home pattern" , t1,r , lpSum( x12[(t1,t2,r)] for t2 in basicTeams if (t1,t2) in games ))
model += lpSum( x12[(t1,t2,r)] for t2 in basicTeams if (t1,t2) in games )== homePat[t1,r]
relRounds = [ r2 for r2 in basicRounds if r2>=r and r2<=r+thisSeason.maxTourLength/(defaultGameRepetions*tripStartHeuristicGroupsize)]
# print(len(relRounds) , thisSeason.maxTourLength/(defaultGameRepetions*tripStartHeuristicGroupsize)+1)
if not usePatterns and not haSymmetric and len(relRounds)==thisSeason.maxTourLength/(defaultGameRepetions*tripStartHeuristicGroupsize)+1:
for t in realBasicTeams:
# print (getTeamById[t])
model += lpSum( homePat[t,r2] for r2 in relRounds) >= 1
model += lpSum( awayPat[t,r2] for r2 in relRounds) >= 1
print (" At least one home/away for " , getTeamById[ t], " in round ", relRounds)
# print (lpSum( homePat[t1,r2] for r2 in relRounds))
# print ("+++++ " , r<=nRounds1 , r+thisSeason.minRoundsBetweenGameOfSameTeams>nRounds1 , not haSymmetric )
# if r<=nRounds1 and r+thisSeason.minRoundsBetweenGameOfSameTeams>nRounds1 and not thisSeason.symmetry :
# relRounds = [ r2 for r2 in basicRounds if r2>=r and r2<=r+thisSeason.minRoundsBetweenGameOfSameTeams ]
# for (t1,t2) in games:
# if (t2,t1) in games and t1<t2 and t2 in realBasicTeams:
# model += lpSum( x11[(t1,t2,r)]+x11[(t2,t1,r)] for r in relRounds )<= 1 + gamesTooClose1[t1,t2]
# gamesTooClose1[t1,t2].upBound=0.0
# print ("no repetitions in rounds ", relRounds , " for ", t1,t2, t1<t2, getTeamById[t1], getTeamById[t2])
# model+=gew['Blockings']*(blockingVio1)
# model.solve(XPRESS(msg=1,maxSeconds = 40))
print ("phases", phases , ", haSymmetric" , haSymmetric )
# exit(0)
for (t1,t2) in games:
if t1 in basicTeams and t2 in basicTeams:
# print (getTeamById[t1], " - " , getTeamById[ t2], " happens ",int(gameCntr[(t1,t2)]/defaultGameRepetions) , " times in ", basicRounds)
model += lpSum( x11[(t1,t2,r)] for r in basicRounds if (t1,t2,r) in x11.keys() )<= int((gameCntr[(t1,t2)]+undirectedGameCntr[(t1,t2)] ) /defaultGameRepetions)
# Objective1=gew['Home-/Away']*HawVio1Total \
# + gew['Blockings']*(blockingVio1 + tooManyHomesInStadiumTotal1) \
# + 1000*lpSum( gamesTooClose1[(t1,t2)] for (t1,t2) in games ) \
# + gew['Pairings']*pairingVioTotal1 \
# + sum([ nBreaksOfPat[p]*assignPattern[p,t,ph] for p in patternRange for t in basicTeams for ph in preplan_phases])\
# + sum([ wg * homePat[t1,getBasicRound[r]] for (t1,t2,r,wg) in otherScenGames ])
Objective1 = 0 \
+ sum([ nBreaksOfPat[p]*assignPattern[p,t,ph] for p in patternRange for t in basicTeams for ph in preplan_phases])\
# + sum([ wg * homePat[t1,getBasicRound[r]] for (t1,t2,r,wg) in otherScenGames ])
model += Objective1
with open (f"model_xpress.txt", "w") as f:
f.write(model.__repr__())
# %%
print ('#########################################')
print ('# SOLVING MODEL 1 (PATTERN ASSIGNMENT) #')
print ('#########################################')
msg=1
if solver == "CBC":
model.solve(PULP_CBC_CMD(fracGap = gap, maxSeconds = comptime, threads = 8,msg=msg))
elif solver == "Gurobi":
model.solve(GUROBI(MIPGap=gap, TimeLimit=comptime,msg=msg))
else:
# model.solve(PULP_CBC_CMD(fracGap = gap, maxSeconds = comptime, threads = 8,msg=1))
model.solve(XPRESS(msg=msg, targetGap=0.01, maxSeconds = comptime, keepFiles=True))
# print ("Home-/Away : " , gew['Home-/Away'], "*",HawVio1Total.value())
# print ("Blockings :" , gew['Blockings'], "*", blockingVio1.value(),tooManyHomesInStadiumTotal1.value())
# print ("Pairings :" , gew['Pairings'], "*", pairingVioTotal1.value())
# print ("Encounters :" , gew['Encounters'], "*",encVio1Total.value())
# print ("totalDistanceSaved :" , gew['Trips'], "*",totalDistanceSaved1.value())
print ("Breaks : 1.0 * ", sum([ nBreaksOfPat[p]*assignPattern[p,t,ph].value() for p in patternRange for t in basicTeams for ph in preplan_phases ]))
print ("Violated Blockings out of " , nBlockingHome )
# %%
home_dict = {}
away_dict = {}
missing_games = []
# for key in x11.keys():
# if type(x11[key]) != int and x11[key].value() > 0:
# home_dict[key[2],key[0]] = key[1]
# away_dict[key[2],key[1]] = key[0]
for key in x12.keys():
if type(x12[key]) != int and x12[key].value() > 0:
home_dict[key[2],key[0]] = key[1]
away_dict[key[2],key[1]] = key[0]
# for key in missingGamesVio.keys():
# if type(missingGamesVio[key]) != int and missingGamesVio[key].value() > 0:
# missing_games.append((t_shortname[split_key[0]],t_shortname[split_key[1]]))
sol = " \
<style> \
table, th, td { \
border: 1px solid black; \
border-collapse: collapse; \
} \
</style> \
"
sol += "<table style='border:1px solid black'>\n"
sol += "<thead>\n"
sol += "<tr><th></th>"
for r in rounds:
sol += f"<th>{r}</th>"
sol += "</tr>"
sol += "</thead>\n"
sol += "<tbody>\n"
for t in teams:
tname = t_shortname[t]
sol += f"<tr><td>{tname}</td>"
for r in rounds:
if (r,t) in home_dict.keys():
opponent = t_shortname[home_dict[(r,t)]]
sol += f"<td style='background-color:lightsteelblue'>{opponent}</td>"
elif (r,t) in away_dict.keys():
opponent = t_shortname[away_dict[(r,t)]]
sol += f"<td style='background-color:lightyellow'>{opponent}</td>"
else:
sol += "<td></td>"
sol += "</tr>"
sol += "</tbody>\n"
sol += "</table>\n"
sol += "<br><br><br>\n"
# for game in missing_games:
# sol += f'{game}<br>\n'
with open('xpress_sol.html', 'w') as f:
f.write(sol)
# %%
from ortools.sat.python import cp_model
"""Minimal CP-SAT example to showcase calling the solver."""
# Creates the model.
sat_model = cp_model.CpModel()
# Creates the variables.
# x = model.NewBoolVar('x')
# y = model.NewBoolVar('y')
# z = model.NewBoolVar('z')
sat = {}
for var in model.variables():
sat[str(var)] = sat_model.NewBoolVar(f'var')
# %%
for ckey,cval in model.constraints.items():
cons_dict = cval.toDict()
vars = cons_dict['coefficients']
sense = cons_dict['sense']
constant = cons_dict['constant']
if sense == -1:
sat_model.Add(sum(var['value']*sat[var['name']] for var in vars) + constant <= 0)
elif sense == 0:
sat_model.Add(sum(var['value']*sat[var['name']] for var in vars) + constant == 0)
elif sense == 1:
sat_model.Add(sum(var['value']*sat[var['name']] for var in vars) + constant >= 0)
objective_terms = []
# for var in model2.objective.toDict():
# objective_terms.append(var['value']*sat[var['name']])
sat_model.Minimize(sum(objective_terms))
# %%
# # Creates the constraints.
# # one_game_in_round
# for ckey,cval in model2.constraints.items():
# if cval.sense == -1:
# vars_in_cons = cval.toDict()['coefficients']
# model.AddAtMostOne(sat[i['name']] for i in vars_in_cons)
# # for q in itertools.combinations(vars_in_cons,2):
# # qubo_prob.objective += -1*qubos[q[0]['name']]*qubos[q[1]['name']]
# # let_play_gameCntr_times
# for ckey,cval in model2.constraints.items():
# if cval.sense == 0:
# vars_in_cons = cval.toDict()['coefficients']
# model.AddExactlyOne(sat[i['name']] for i in vars_in_cons)
# objective_terms = []
# for var in model2.objective:
# objective_terms.append(sat[str(var)])
# model.Minimize(sum(objective_terms))
# %%
print("STARTING SAT-SOLVER")
# Creates a solver and solves the model.
solver = cp_model.CpSolver()
solver.parameters.log_search_progress = True
print("STARTING SAT-SOLVER")
status = solver.Solve(sat_model)
# %%
home_dict = {}
away_dict = {}
missing_games = []
for key in sat.keys():
if solver.BooleanValue(sat[key]):
split_key = key.split('_')
if split_key[0] == 'x':
home_dict[int(split_key[4]),int(split_key[2])] = int(split_key[3])
away_dict[int(split_key[4]),int(split_key[3])] = int(split_key[2])
elif split_key[0] == 'missingGamesVio':
missing_games.append((t_shortname[int(split_key[1])],t_shortname[int(split_key[2])]))
sol = " \
<style> \
table, th, td { \
border: 1px solid black; \
border-collapse: collapse; \
} \
</style> \
"
sol += "<table style='border:1px solid black'>\n"
sol += "<thead>\n"
sol += "<tr><th></th>"
for r in rounds:
sol += f"<th>{r}</th>"
sol += "</tr>"
sol += "</thead>\n"
sol += "<tbody>\n"
for t in teams:
tname = t_shortname[t]
sol += f"<tr><td>{tname}</td>"
for r in rounds:
if (r,t) in home_dict.keys():
opponent = t_shortname[home_dict[(r,t)]]
sol += f"<td style='background-color:lightsteelblue'>{opponent}</td>"
elif (r,t) in away_dict.keys():
opponent = t_shortname[away_dict[(r,t)]]
sol += f"<td style='background-color:lightyellow'>{opponent}</td>"
else:
sol += "<td></td>"
sol += "</tr>"
sol += "</tbody>\n"
sol += "</table>\n"
sol += "<br><br><br>\n"
for game in missing_games:
sol += f'{game}<br>\n'
with open('sat_sol.html', 'w') as f:
f.write(sol)
# %%
# %%
API_KEY = 'AJwxeJRRZtJ9rOKVGTV6ruvG9TvC1wnE'
from quantagonia.qubo import QuboModel
from quantagonia.enums import HybridSolverConnectionType
from quantagonia.runner import Runner
from quantagonia.runner_factory import RunnerFactory
from quantagonia.spec_builder import QuboSolverType, QUBOSpecBuilder
spec = QUBOSpecBuilder()
spec.set_time_limit(time_limit=600)
runner = RunnerFactory.getRunner(HybridSolverConnectionType.CLOUD, api_key=API_KEY)
# %%
qubo_prob = QuboModel()
qubos = {}
for var in model.variables():
qubos[str(var)] = qubo_prob.addVariable(f"{var}", initial=0)
for var in model.objective:
qubo_prob.objective += -1*qubos[str(var)]
for ckey,cval in model.constraints.items():
if cval.sense == -1:
vars_in_cons = cval.toDict()['coefficients']
for q in itertools.combinations(vars_in_cons,2):
qubo_prob.objective += -1*qubos[q[0]['name']]*qubos[q[1]['name']]
for ckey,cval in model.constraints.items():
if cval.sense == 0:
qubo_prob.objective += 1
vars_in_cons = cval.toDict()['coefficients']
for var in vars_in_cons:
qubo_prob.objective += -1*-1*qubos[var['name']]
for q in itertools.combinations(vars_in_cons,2):
qubo_prob.objective += -1*2*qubos[q[0]['name']]*qubos[q[1]['name']]
with open('model_qubo.txt','w') as f:
f.write(str(qubo_prob))
status = qubo_prob.solve(spec.getd(), runner=runner)
# %%
home_dict = {}
away_dict = {}
missing_games = []
for key in qubo_prob.vars.keys():
if qubo_prob.vars[key].eval() > 0:
split_key = key.split('_')
if split_key[0] == 'x':
home_dict[int(split_key[4]),int(split_key[2])] = int(split_key[3])
away_dict[int(split_key[4]),int(split_key[3])] = int(split_key[2])
elif split_key[0] == 'missingGamesVio':
missing_games.append((t_shortname[int(split_key[1])],t_shortname[int(split_key[2])]))
sol = " \
<style> \
table, th, td { \
border: 1px solid black; \
border-collapse: collapse; \
} \
</style> \
"
sol += "<table style='border:1px solid black'>\n"
sol += "<thead>\n"
sol += "<tr><th></th>"
for r in rounds:
sol += f"<th>{r}</th>"
sol += "</tr>"
sol += "</thead>\n"
sol += "<tbody>\n"
for t in teams:
tname = t_shortname[t]
sol += f"<tr><td>{tname}</td>"
for r in rounds:
if (r,t) in home_dict.keys():
opponent = t_shortname[home_dict[(r,t)]]
sol += f"<td style='background-color:lightsteelblue'>{opponent}</td>"
elif (r,t) in away_dict.keys():
opponent = t_shortname[away_dict[(r,t)]]
sol += f"<td style='background-color:lightyellow'>{opponent}</td>"
else:
sol += "<td></td>"
sol += "</tr>"
sol += "</tbody>\n"
sol += "</table>\n"
sol += "<br><br><br>\n"
for game in missing_games:
sol += f'{game}<br>\n'
with open('qubo_sol.html', 'w') as f:
f.write(sol)