# %% 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-b11: 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= 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 t10: # 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 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 = " \ \ " sol += "\n" sol += "\n" sol += "" for r in rounds: sol += f"" sol += "" sol += "\n" sol += "\n" for t in teams: tname = t_shortname[t] sol += f"" for r in rounds: if (r,t) in home_dict.keys(): opponent = t_shortname[home_dict[(r,t)]] sol += f"" elif (r,t) in away_dict.keys(): opponent = t_shortname[away_dict[(r,t)]] sol += f"" else: sol += "" sol += "" sol += "\n" sol += "
{r}
{tname}{opponent}{opponent}
\n" sol += "


\n" # for game in missing_games: # sol += f'{game}
\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 = " \ \ " sol += "\n" sol += "\n" sol += "" for r in rounds: sol += f"" sol += "" sol += "\n" sol += "\n" for t in teams: tname = t_shortname[t] sol += f"" for r in rounds: if (r,t) in home_dict.keys(): opponent = t_shortname[home_dict[(r,t)]] sol += f"" elif (r,t) in away_dict.keys(): opponent = t_shortname[away_dict[(r,t)]] sol += f"" else: sol += "" sol += "" sol += "\n" sol += "
{r}
{tname}{opponent}{opponent}
\n" sol += "


\n" for game in missing_games: sol += f'{game}
\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 = " \ \ " sol += "\n" sol += "\n" sol += "" for r in rounds: sol += f"" sol += "" sol += "\n" sol += "\n" for t in teams: tname = t_shortname[t] sol += f"" for r in rounds: if (r,t) in home_dict.keys(): opponent = t_shortname[home_dict[(r,t)]] sol += f"" elif (r,t) in away_dict.keys(): opponent = t_shortname[away_dict[(r,t)]] sol += f"" else: sol += "" sol += "" sol += "\n" sol += "
{r}
{tname}{opponent}{opponent}
\n" sol += "


\n" for game in missing_games: sol += f'{game}
\n' with open('qubo_sol.html', 'w') as f: f.write(sol)