1857 lines
73 KiB
Python
Executable File
1857 lines
73 KiB
Python
Executable File
# %%
|
|
import os, sys
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
# %%
|
|
|
|
if os.environ.get("SERVER", None):
|
|
PROJECT_PATH = "/home/django/leagues/"
|
|
else:
|
|
PROJECT_PATH = "/home/md/Work/ligalytics/leagues_stable/"
|
|
|
|
import os, sys
|
|
import json
|
|
from numpyencoder import NumpyEncoder
|
|
|
|
|
|
sys.path.insert(0, PROJECT_PATH)
|
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "leagues.settings")
|
|
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
|
|
|
from leagues import settings
|
|
|
|
# settings.DATABASES['default']['NAME'] = PROJECT_PATH+'/db.sqlite3'
|
|
if os.environ.get("SERVER", None):
|
|
settings.DATABASES["default"]["ENGINE"] = "django.db.backends.postgresql"
|
|
settings.DATABASES["default"]["HOST"] = "0.0.0.0"
|
|
settings.DATABASES["default"]["PORT"] = "5433"
|
|
settings.DATABASES["default"]["USER"] = "leagues_user"
|
|
settings.DATABASES["default"]["PASSWORD"] = "ligalytics"
|
|
settings.DATABASES["default"]["NAME"] = "prod_16"
|
|
else:
|
|
settings.DATABASES["default"]["NAME"] = PROJECT_PATH + "/db.sqlite3"
|
|
settings.DATABASES["default"]["ENGINE"] = "django.db.backends.postgresql"
|
|
settings.DATABASES["default"]["HOST"] = "0.0.0.0"
|
|
settings.DATABASES["default"]["PORT"] = "5432"
|
|
settings.DATABASES["default"]["USER"] = "postgres"
|
|
settings.DATABASES["default"]["PASSWORD"] = "secret123"
|
|
settings.DATABASES["default"]["NAME"] = "mypgsqldb"
|
|
settings.DATABASES["default"]["ATOMIC_REQUESTS"] = False
|
|
settings.DATABASES["default"]["AUTOCOMMIT"] = True
|
|
settings.DATABASES["default"]["CONN_MAX_AGE"] = 0
|
|
settings.DATABASES["default"]["CONN_HEALTH_CHECKS"] = False
|
|
settings.DATABASES["default"]["OPTIONS"] = {}
|
|
|
|
|
|
os.environ["XPRESSDIR"] = "/opt/xpressmp"
|
|
os.environ["XPRESS"] = "/opt/xpressmp/bin"
|
|
os.environ["LD_LIBRARY_PATH"] = os.environ["XPRESSDIR"] + "/lib"
|
|
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["CLASSPATH"] = os.environ["XPRESSDIR"] + "/lib/xprs.jar"
|
|
os.environ["CLASSPATH"] = (
|
|
os.environ["XPRESSDIR"] + "/lib/xprb.jar" + os.pathsep + os.environ["CLASSPATH"]
|
|
)
|
|
os.environ["CLASSPATH"] = (
|
|
os.environ["XPRESSDIR"] + "/lib/xprm.jar" + os.pathsep + os.environ["CLASSPATH"]
|
|
)
|
|
os.environ["PATH"] = os.environ["XPRESSDIR"] + "/bin" + os.pathsep + os.environ["PATH"]
|
|
|
|
|
|
import django
|
|
|
|
django.setup()
|
|
|
|
|
|
# %%
|
|
|
|
from scheduler.models import *
|
|
from scheduler.helpers import *
|
|
|
|
# from scheduler.solver.optimizer import optimize_2phases
|
|
from scheduler.solver.tasks.optimize import optimize
|
|
|
|
|
|
# %%
|
|
|
|
import copy
|
|
from collections import defaultdict
|
|
from unittest import TextTestResult
|
|
from ortools.sat.python import cp_model
|
|
from pulp import *
|
|
import random
|
|
import os
|
|
import time
|
|
import pandas as pd
|
|
from math import sqrt, sin, cos, atan2, pi
|
|
import numpy as np
|
|
|
|
# XPRESS ENVIRONMENT
|
|
os.environ["XPRESSDIR"] = "/opt/xpressmp_9.5.0"
|
|
os.environ["XPRESS"] = "/opt/xpressmp_9.5.0/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"]
|
|
|
|
import xpress as xp
|
|
|
|
xp.controls.outputlog = 0
|
|
|
|
|
|
import datetime
|
|
from dateutil.parser import parse
|
|
|
|
|
|
def Availabilities(scenario_id, showSolution="0"):
|
|
tt = time.time()
|
|
sc = Scenario.objects.get(id=scenario_id)
|
|
teams = (
|
|
Team.objects.filter(season=sc.season, active=True)
|
|
.order_by("name")
|
|
.exclude(name="-")
|
|
)
|
|
realteams = [t.id for t in teams]
|
|
getTeamById = {t.id: t for t in teams}
|
|
t_short = {t.id: t.shortname for t in teams}
|
|
blockings = (
|
|
Blocking.objects.filter(scenario=sc, team__active=True)
|
|
.exclude(day__round=0)
|
|
.order_by("day", "team")
|
|
.annotate(
|
|
dayID=F("day__id"),
|
|
teamID=F("team__id"),
|
|
)
|
|
)
|
|
days = Day.objects.filter(season=sc.season).order_by("day", "round")
|
|
|
|
getDay = {d.id: d for d in days}
|
|
getDateTimeDay = {d.id: "" for d in days}
|
|
for d in days:
|
|
if d.day[0] != "R":
|
|
getDateTimeDay[d.id] = parse(d.day)
|
|
|
|
getDayByDateTime = {getDateTimeDay[d.id]: d for d in days}
|
|
daysSorted = []
|
|
for dt in sorted([getDateTimeDay[d.id] for d in days]):
|
|
daysSorted.append(getDayByDateTime[dt])
|
|
|
|
usedDays = getDateTimeDay.values()
|
|
for d in daysSorted:
|
|
d.firstDayInSequence = (
|
|
getDateTimeDay[d.id] - datetime.timedelta(days=1)
|
|
) not in usedDays
|
|
|
|
nRounds = sc.season.nRounds
|
|
rounds = range(1, nRounds + 1)
|
|
breaks = Break.objects.filter(season=sc.season).values()
|
|
|
|
# SLOWING VIEW DOWN
|
|
# for bl in blockings:
|
|
# if bl.day.round==0 or not bl.team.active:
|
|
# bl.delete()
|
|
# print ("blocking not assigned to round: deleting " , bl)
|
|
blockings.filter(day__round=0).exclude(team__active=False).delete()
|
|
|
|
blockRefreshNecessary = False
|
|
blockDict = defaultdict(dict)
|
|
for bl in blockings:
|
|
if not blockDict[(bl.dayID, bl.teamID)]:
|
|
blockDict[(bl.dayID, bl.teamID)] = bl
|
|
else:
|
|
if (
|
|
blockDict[(bl.dayID, bl.teamID)].type == "Home" and bl.type == "Away"
|
|
) or (
|
|
blockDict[(bl.dayID, bl.teamID)].type == "Away" and bl.type == "Home"
|
|
):
|
|
blockDict[(bl.dayID, bl.teamID)].type = "Game"
|
|
blockDict[(bl.dayID, bl.teamID)].tag = None
|
|
blockDict[(bl.dayID, bl.teamID)].save()
|
|
bl.delete()
|
|
blockRefreshNecessary = True
|
|
|
|
if blockRefreshNecessary:
|
|
blockings = (
|
|
Blocking.objects.filter(scenario=sc, team__active=True)
|
|
.exclude(day__round=0)
|
|
.order_by("day", "team")
|
|
.annotate(
|
|
dayID=F("day__id"),
|
|
teamID=F("team__id"),
|
|
)
|
|
)
|
|
|
|
isBlocked = {
|
|
(d.id, t.id, ha): False for t in teams for d in days for ha in ["H", "A"]
|
|
}
|
|
isBlockedTags = {
|
|
(d.id, t.id, ha): [] for t in teams for d in days for ha in ["H", "A"]
|
|
}
|
|
blockComment = defaultdict(dict)
|
|
for bl in blockings:
|
|
if bl.tag:
|
|
if bl.tag.blocking_weight < 0.0:
|
|
continue
|
|
isBlockedTags[(bl.day.id, bl.team.id, "H")].append(bl.tag.name)
|
|
if bl.comment not in ["", "-"]:
|
|
blockComment[int(bl.day.id)][int(bl.team.id)] = bl.comment
|
|
if bl.type != "Home":
|
|
isBlocked[(int(bl.day.id), int(bl.team.id), "A")] = True
|
|
if bl.type != "Away":
|
|
isBlocked[(bl.day.id, bl.team.id, "H")] = True
|
|
|
|
# print ("isBlocked",isBlocked)
|
|
|
|
for b in blockings.exclude(comment__in=["", "-"]):
|
|
blockComment[int(b.day.id)][int(b.team.id)] = b.comment
|
|
|
|
stadiums = Stadium.objects.filter(season=sc.season)
|
|
stadiumblockings = StadiumBlocking.objects.filter(scenario=sc, stadium__in=stadiums)
|
|
|
|
# print ("stadiumblockings",stadiumblockings)
|
|
|
|
groups = Conference.objects.filter(scenario=sc, display_teams=True).order_by("name")
|
|
# firstTeams = [ g.teams.all().order_by('name').first().id for g in groups]
|
|
firstTeams = []
|
|
for g in groups:
|
|
tms = [(t.name, t.id) for t in g.teams.all()]
|
|
tms.sort()
|
|
firstTeams.append(tms[0][1])
|
|
|
|
wd = {
|
|
"Mondays": 0,
|
|
"Tuesdays": 1,
|
|
"Wednesdays": 2,
|
|
"Thursdays": 3,
|
|
"Fridays": 4,
|
|
"Saturdays": 5,
|
|
"Sundays": 6,
|
|
}
|
|
t_possible_weekdays = {t.id: [] for t in teams}
|
|
t_available_slot_per_weekday = {(t.id, w): 0 for t in teams for w in wd.keys()}
|
|
t_stadiums = {t.id: [] for t in teams}
|
|
t_site_available = {(t.id, d.id): 0 for t in teams for d in days}
|
|
for t in teams:
|
|
# print ("checking stadium availabilities for " , t.name)
|
|
t_stadiums[t.id] = [sts.stadium for sts in t.stadiumpreferences.all()]
|
|
for stsp in t.stadiumTimeSlotPreferences.all():
|
|
t_possible_weekdays[t.id].append(wd[stsp.stadiumTimeSlot.weekday])
|
|
blockedDays = [
|
|
sb.day
|
|
for sb in stsp.stadiumTimeSlot.stadiumtimeslotblockings.all().exclude(
|
|
homeTeam_id__in=teams
|
|
)
|
|
]
|
|
for d in days:
|
|
if (
|
|
getDateTimeDay[d.id].weekday() == wd[stsp.stadiumTimeSlot.weekday]
|
|
and d.day not in blockedDays
|
|
):
|
|
t_site_available[(t.id, d.id)] += 1
|
|
stadiumBlocks = [
|
|
(tid, did)
|
|
for (tid, did) in t_site_available.keys()
|
|
if t_site_available[(tid, did)] == 0 and t_possible_weekdays[tid] != []
|
|
]
|
|
# for t,d in stadiumBlocks:
|
|
# print (getDateTimeDay[d], [ t2.name for t2 in teams if t2.id==t])
|
|
|
|
competitions = InternationalGame.objects.filter(season=sc.season, active=True)
|
|
playDays = [day.id for day in days if day.maxGames > 0 and day.round > 0]
|
|
compDays = {}
|
|
competitionBlocks = []
|
|
for c in competitions:
|
|
c.blocking_weight = 0.5
|
|
compDays[c.id] = []
|
|
dayBefore = datetime.timedelta(days=c.nDaysNotPlayBefore)
|
|
dayAfter = datetime.timedelta(days=c.nDaysNotPlayAfter)
|
|
for d in c.days.all():
|
|
firstDay = getDateTimeDay[d.id] - dayBefore
|
|
lastDay = getDateTimeDay[d.id] + dayAfter
|
|
compDays[c.id] += [
|
|
d2 for d2 in playDays if firstDay <= getDateTimeDay[d2] <= lastDay
|
|
]
|
|
compDays[c.id] = list(set(compDays[c.id]))
|
|
for t in c.teams.all():
|
|
for d in compDays[c.id]:
|
|
competitionBlocks.append((t.id, d))
|
|
for tp in ["H", "A"]:
|
|
isBlocked[(d, t.id, tp)] = True
|
|
isBlockedTags[(d, t.id, tp)].append(c.name)
|
|
|
|
if sc.season.useFeatureKickOffTime:
|
|
currentSolution = [
|
|
(int(sl[1]), int(sl[2]), int(sl[3]), int(sl[0]), sl[4])
|
|
for sl in sc.solutionlist()
|
|
if len(sl) > 4
|
|
]
|
|
else:
|
|
currentSolution = [
|
|
(int(sl[1]), int(sl[2]), int(sl[3]), int(sl[0]))
|
|
for sl in sc.solutionlist()
|
|
if len(sl) > 3
|
|
]
|
|
|
|
currentSolutionOfDay = {d.id: [] for d in days}
|
|
currentSolutionInRound = {(t, r): "" for t in realteams for r in rounds}
|
|
currentSolutionAtDay = {(t, d.id): "" for t in realteams for d in days}
|
|
currentSolutionTimeAtDay = {(t, d.id): "" for t in realteams for d in days}
|
|
currentSolutionTimeAtDayCode = {(t, d.id): "" for t in realteams for d in days}
|
|
currentSolutionDayOfTeamRound = {(t, r): 0 for t in realteams for r in rounds}
|
|
games = {}
|
|
shortGames = defaultdict(dict)
|
|
violations = []
|
|
fullHaName = {"H": "Home", "A": "Away"}
|
|
for cs in currentSolution:
|
|
(t1, t2, r, d) = (cs[0], cs[1], cs[2], cs[3])
|
|
if d in currentSolutionOfDay.keys():
|
|
currentSolutionInRound[(t1, r)] = "H"
|
|
currentSolutionInRound[(t2, r)] = "A"
|
|
currentSolutionAtDay[(t1, d)] = "H"
|
|
currentSolutionAtDay[(t2, d)] = "A"
|
|
currentSolutionOfDay[d].append((t1, t2, r))
|
|
currentSolutionDayOfTeamRound[(t1, r)] = d
|
|
currentSolutionDayOfTeamRound[(t2, r)] = d
|
|
if sc.season.useFeatureKickOffTime:
|
|
currentSolutionTimeAtDay[(t1, d)] = cs[4]
|
|
currentSolutionTimeAtDay[(t2, d)] = cs[4]
|
|
ts = TimeSlot.objects.filter(season=sc.season, name=cs[4]).first()
|
|
if ts:
|
|
currentSolutionTimeAtDayCode[(t1, d)] = ts.code
|
|
currentSolutionTimeAtDayCode[(t2, d)] = ts.code
|
|
for t3 in [t1, t2]:
|
|
color = (
|
|
"red" if isBlocked[(d, t3, currentSolutionAtDay[(t3, d)])] else ""
|
|
)
|
|
games[str(d) + "_" + str(t3)] = (
|
|
currentSolutionAtDay[(t3, d)]
|
|
+ currentSolutionTimeAtDayCode[(t3, d)],
|
|
color,
|
|
)
|
|
shortGames[d][t3] = t_short[t1] + "-" + t_short[t2]
|
|
if color == "red":
|
|
violations.append(
|
|
(
|
|
getTeamById[t3],
|
|
getDay[d],
|
|
fullHaName[currentSolutionAtDay[(t3, d)]],
|
|
currentSolutionTimeAtDay[(t3, d)],
|
|
", ".join(
|
|
isBlockedTags[(d, t3, currentSolutionAtDay[(t3, d)])]
|
|
),
|
|
)
|
|
)
|
|
|
|
for bl in blockings:
|
|
if (
|
|
bl.tag
|
|
and bl.tag.blocking_weight < 0.0
|
|
and currentSolutionAtDay[(bl.team.id, bl.day.id)] != "H"
|
|
):
|
|
violations.append(
|
|
(getTeamById[bl.team.id], getDay[bl.day.id], "Home", "", bl.tag.name)
|
|
)
|
|
|
|
redStripes = []
|
|
missingBreaks = []
|
|
for bl in breaks:
|
|
for t in realteams:
|
|
if currentSolutionInRound[(t, bl["round1"])] == currentSolutionInRound[
|
|
(t, bl["round2"])
|
|
] and currentSolutionInRound[(t, bl["round1"])] in ["H", "A"]:
|
|
redStripes.append(
|
|
str(currentSolutionDayOfTeamRound[(t, bl["round1"])])
|
|
+ "_"
|
|
+ str(t)
|
|
+ "__"
|
|
+ str(currentSolutionDayOfTeamRound[(t, bl["round2"])])
|
|
+ "_"
|
|
+ str(t)
|
|
)
|
|
else:
|
|
missingBreaks.append(t)
|
|
|
|
if showSolution == "0":
|
|
games = []
|
|
redStripes = []
|
|
violations = []
|
|
shortGames = {}
|
|
|
|
context = {
|
|
# 'blockings1' : blockings1,
|
|
# 'games' : games,
|
|
# 'shortGames' : shortGames,
|
|
"violations": violations,
|
|
# 'firstTeams' : firstTeams,
|
|
# 'blockings' : blockings,
|
|
# 'stadiumBlocks' : stadiumBlocks,
|
|
# 'competitionBlocks' : competitionBlocks,
|
|
# 'groups' : groups,
|
|
# 'days' : daysSorted,
|
|
# 'teams' : teams,
|
|
# 'comments': blockComment,
|
|
# 'redStripes': redStripes,
|
|
# 'tags': Tag.objects.filter(season=sc.season).exclude(blocking_weight=0),
|
|
# 'stadiums' : stadiums,
|
|
# 'stadiumblockings' : stadiumblockings,
|
|
# 'showStadiums' : showSolution=="0",
|
|
"missingBreaks": missingBreaks,
|
|
}
|
|
|
|
return context
|
|
|
|
|
|
class Draw_Simulator:
|
|
def __init__(
|
|
self, algorithm, opponent_func, html_output, use_db=False, use_chess=False, suffix="", opt_param="", scenario_id=None
|
|
):
|
|
|
|
self.chess = use_chess
|
|
self.blue_groups = []
|
|
self.red_groups = []
|
|
self.suffix = suffix
|
|
self.opt_param = opt_param
|
|
self.scenario_id = scenario_id
|
|
if self.chess:
|
|
|
|
# basepots {'D': [
|
|
# {'id': 47715, 'pot': 'D', 'name': 'Rouen Dragons', 'country': 'France', 'coeff': 2.0, 'lat': 49.443232, 'lon': 1.099971},
|
|
# {'id': 47747, 'pot': 'D', 'name': 'Fehérvár AV19', 'country': 'Austria', 'coeff': 3.0, 'lat': 47.1860262, 'lon': 18.4221358},
|
|
# {'id': 52169, 'pot': 'D', 'name': 'Sheffield Steelers', 'country': 'United Kingdom', 'coeff': 3.0, 'lat': 53.38112899999999, 'lon': -1.470085},
|
|
# {'id': 52170, 'pot': 'D', 'name': 'SønderjyskE Vojens', 'country': 'Denmark', 'coeff': 1.0, 'lat': 55.249489, 'lon': 9.3019649},
|
|
# {'id': 52171, 'pot': 'D', 'name': 'Unia Oświęcim', 'country': 'Poland', 'coeff': 1.0, 'lat': 50.0343982, 'lon': 19.2097782},
|
|
# {'id': 47741, 'pot': 'D', 'name': 'Storhamar Hamar', 'country': 'Norway', 'coeff': 1.0, 'lat': 60.794442, 'lon': 11.0442983}], 'C': [
|
|
# {'id': 52167, 'pot': 'C', 'name': 'KAC Klagenfurt', 'country': 'Austria', 'coeff': 3.0, 'lat': 46.625704, 'lon': 14.3137371},
|
|
# {'id': 47742, 'pot': 'C', 'name': 'Växjö Lakers', 'country': 'Sweden', 'coeff': 4.0, 'lat': 56.8790044, 'lon': 14.8058522},
|
|
# {'id': 47743, 'pot': 'C', 'name': 'Straubing Tigers', 'country': 'Germany', 'coeff': 4.0, 'lat': 48.8777333, 'lon': 12.5801538},
|
|
# {'id': 47755, 'pot': 'C', 'name': 'Sparta Prague', 'country': 'Czechia', 'coeff': 4.0, 'lat': 50.0755381, 'lon': 14.4378005},
|
|
# {'id': 52168, 'pot': 'C', 'name': 'Lausanne HC', 'country': 'Switzerland', 'coeff': 3.0, 'lat': 46.5196535, 'lon': 6.6322734},
|
|
# {'id': 47737, 'pot': 'C', 'name': 'Lahti Pelicans', 'country': 'Finland', 'coeff': 2.0, 'lat': 60.9826749, 'lon': 25.6612096}], 'B': [
|
|
# {'id': 52166, 'pot': 'B', 'name': 'Pinguins Bremerhaven', 'country': 'Germany', 'coeff': 4.0, 'lat': 53.5395845, 'lon': 8.5809424},
|
|
# {'id': 47761, 'pot': 'B', 'name': 'Red Bull Salzburg', 'country': 'Austria', 'coeff': 3.0, 'lat': 47.80949, 'lon': 13.05501},
|
|
# {'id': 47724, 'pot': 'B', 'name': 'Ilves Tampere', 'country': 'Finland', 'coeff': 4.0, 'lat': 61.4977524, 'lon': 23.7609535},
|
|
# {'id': 47735, 'pot': 'B', 'name': 'Dynamo Pardubice', 'country': 'Czechia', 'coeff': 4.0, 'lat': 50.0343092, 'lon': 15.7811994},
|
|
# {'id': 47740, 'pot': 'B', 'name': 'Färjestad Karlstad', 'country': 'Sweden', 'coeff': 4.0, 'lat': 59.4002601, 'lon': 13.5009352},
|
|
# {'id': 47717, 'pot': 'B', 'name': 'Fribourg-Gottéron', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 46.8064773, 'lon': 7.1619719}], 'A': [
|
|
# {'id': 47721, 'pot': 'A', 'name': 'Eisbären Berlin', 'country': 'Germany', 'coeff': 4.0, 'lat': 52.5200066, 'lon': 13.404954},
|
|
# {'id': 47719, 'pot': 'A', 'name': 'ZSC Lions Zurich', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 47.4124497, 'lon': 8.5578995},
|
|
# {'id': 47756, 'pot': 'A', 'name': 'Oceláři Třinec', 'country': 'Czechia', 'coeff': 4.0, 'lat': 49.677631, 'lon': 18.6707901},
|
|
# {'id': 47757, 'pot': 'A', 'name': 'Skellefteå AIK', 'country': 'Sweden', 'coeff': 4.0, 'lat': 64.750244, 'lon': 20.950917},
|
|
# {'id': 47725, 'pot': 'A', 'name': 'Tappara Tampere', 'country': 'Finland', 'coeff': 4.0, 'lat': 61.4977524, 'lon': 23.7609535},
|
|
# {'id': 47733, 'pot': 'A', 'name': 'Genève-Servette', 'country': 'Switzerland', 'coeff': 4.0, 'lat': 46.2043907, 'lon': 6.1431577}]}
|
|
|
|
# self.blue_teams = ['Sheffield Steelers', 'Fribourg-Gottéron', 'ZSC Lions Zurich']
|
|
|
|
# self.red_teams = ['Sparta Prague']
|
|
|
|
self.blue_teams = [
|
|
'Genève-Servette','Eisbären Berlin','Sheffield Steelers','ZSC Lions Zurich','Fribourg-Gottéron',
|
|
]
|
|
self.red_teams = [
|
|
'Ilves Tampere','Sparta Prague','Tappara Tampere',
|
|
]
|
|
else:
|
|
self.blue_teams = []
|
|
self.red_teams = []
|
|
|
|
self.pots = ["D", "C", "B", "A"]
|
|
|
|
if use_db:
|
|
scenario = Scenario.objects.get(id=self.scenario_id)
|
|
|
|
self.basepots = {
|
|
pot: [
|
|
{
|
|
"id": team.id,
|
|
"pot": pot,
|
|
"name": team.name,
|
|
"country": team.countryObj.name,
|
|
"coeff": team.attractivity,
|
|
"lat": team.latitude,
|
|
"lon": team.longitude,
|
|
}
|
|
for team in Team.objects.filter(
|
|
season=scenario.season, pot=pot_n + 1, active=True
|
|
)
|
|
]
|
|
for pot_n, pot in enumerate(self.pots)
|
|
}
|
|
|
|
df_rank = pd.read_csv("rankings_2.0.csv")
|
|
for pot in self.basepots:
|
|
for team in self.basepots[pot]:
|
|
try:
|
|
ranking = df_rank[df_rank["TEAM"] == team["name"]].iloc[0]
|
|
team["coeff"] = ranking["RANK"]
|
|
except:
|
|
team["coeff"] = 0
|
|
|
|
self.blue_teams = [t.id for t in Team.objects.filter(season=scenario.season,name__in=self.blue_teams)]
|
|
self.red_teams = [t.id for t in Team.objects.filter(season=scenario.season,name__in=self.red_teams)]
|
|
|
|
else:
|
|
self.basepots = {
|
|
"A": [
|
|
{
|
|
"id": 0,
|
|
"pot": "A",
|
|
"name": "Rögle Ängelholm",
|
|
"country": "Sweden",
|
|
},
|
|
{
|
|
"id": 1,
|
|
"pot": "A",
|
|
"name": "Färjestad Karlstad",
|
|
"country": "Sweden",
|
|
},
|
|
{"id": 2, "pot": "A", "name": "EV Zug", "country": "Switzerland"},
|
|
{
|
|
"id": 3,
|
|
"pot": "A",
|
|
"name": "Eisbären Berlin",
|
|
"country": "Germany",
|
|
},
|
|
{
|
|
"id": 4,
|
|
"pot": "A",
|
|
"name": "Tappara Tampere",
|
|
"country": "Finland",
|
|
},
|
|
{
|
|
"id": 5,
|
|
"pot": "A",
|
|
"name": "Oceláři Třinec",
|
|
"country": "Czech Republic",
|
|
},
|
|
],
|
|
"B": [
|
|
{
|
|
"id": 6,
|
|
"pot": "B",
|
|
"name": "Red Bull Salzburg",
|
|
"country": "Austria",
|
|
},
|
|
{"id": 7, "pot": "B", "name": "Lulea Hockey", "country": "Sweden"},
|
|
{
|
|
"id": 8,
|
|
"pot": "B",
|
|
"name": "Fribourg-Gottéron",
|
|
"country": "Switzerland",
|
|
},
|
|
{
|
|
"id": 9,
|
|
"pot": "B",
|
|
"name": "Red Bull Munich",
|
|
"country": "Germany",
|
|
},
|
|
{
|
|
"id": 10,
|
|
"pot": "B",
|
|
"name": "Jukurit Mikkeli",
|
|
"country": "Finland",
|
|
},
|
|
{
|
|
"id": 11,
|
|
"pot": "B",
|
|
"name": "Mountfield HK",
|
|
"country": "Czech Republic",
|
|
},
|
|
],
|
|
"C": [
|
|
{"id": 12, "pot": "C", "name": "VS Villach", "country": "Austria"},
|
|
{
|
|
"id": 13,
|
|
"pot": "C",
|
|
"name": "ZSC Lions Zürich",
|
|
"country": "Switzerland",
|
|
},
|
|
{
|
|
"id": 14,
|
|
"pot": "C",
|
|
"name": "Grizzlys Wolfsburg",
|
|
"country": "Germany",
|
|
},
|
|
{
|
|
"id": 15,
|
|
"pot": "C",
|
|
"name": "Ilves Tampere",
|
|
"country": "Finland",
|
|
},
|
|
{
|
|
"id": 16,
|
|
"pot": "C",
|
|
"name": "Sparta Prague",
|
|
"country": "Czech Republic",
|
|
},
|
|
{
|
|
"id": 17,
|
|
"pot": "C",
|
|
"name": "Fehérvár AV19",
|
|
"country": "Austria",
|
|
},
|
|
],
|
|
"D": [
|
|
{
|
|
"id": 18,
|
|
"pot": "D",
|
|
"name": "Belfast Giants",
|
|
"country": "United Kingdom",
|
|
},
|
|
{"id": 19, "pot": "D", "name": "Grenoble", "country": "France"},
|
|
{"id": 20, "pot": "D", "name": "GKS Katowice", "country": "Poland"},
|
|
{
|
|
"id": 21,
|
|
"pot": "D",
|
|
"name": "Aalborg Pirates",
|
|
"country": "Denmark",
|
|
},
|
|
{
|
|
"id": 22,
|
|
"pot": "D",
|
|
"name": "Stavanger Oilers",
|
|
"country": "Norway",
|
|
},
|
|
{
|
|
"id": 23,
|
|
"pot": "D",
|
|
"name": "Slovan Bratislava",
|
|
"country": "Slovakia",
|
|
},
|
|
],
|
|
}
|
|
|
|
df_rank = pd.read_csv("rankings.csv")
|
|
df_geo = pd.read_csv("geocoord.csv")
|
|
for pot in self.basepots:
|
|
for team in self.basepots[pot]:
|
|
ranking = df_rank[df_rank["TEAM"] == team["name"]].iloc[0]
|
|
team["coeff"] = ranking["RANK"]
|
|
geo = df_geo[df_geo["TEAM"] == team["name"]].iloc[0]
|
|
team["lat"] = geo["LAT"]
|
|
team["lon"] = geo["LON"]
|
|
|
|
self.groups = range(1, len(self.basepots[self.pots[0]]) + 1)
|
|
self.empty_groups = {g: {b: None for b in self.pots} for g in self.groups}
|
|
|
|
teams = []
|
|
id = 0
|
|
for _, plist in self.basepots.items():
|
|
for team in plist:
|
|
teams.append(team)
|
|
id += 1
|
|
|
|
self.teams = teams
|
|
self.countries = set([t["country"] for t in teams])
|
|
self.teams_by_country = {
|
|
c: [v for v in teams if v["country"] == c] for c in self.countries
|
|
}
|
|
|
|
self.distance_matrix = {
|
|
(t1["id"], t2["id"]): Draw_Simulator.distanceInKmByGPS(
|
|
t1["lat"], t1["lon"], t2["lat"], t2["lon"]
|
|
)
|
|
for t1 in self.teams
|
|
for t2 in self.teams
|
|
}
|
|
|
|
self.opponent_func = opponent_func
|
|
self.opponents, self.homeGames, self.awayGames = opponent_func(self)
|
|
|
|
self.algorithm = algorithm
|
|
|
|
self.html_output = html_output
|
|
|
|
@staticmethod
|
|
def distanceInKmByGPS(lat1, lon1, lat2, lon2):
|
|
def degreesToRadians(degrees):
|
|
return degrees * pi / 180
|
|
|
|
earthRadiusKm = 6371
|
|
dLat = degreesToRadians(lat2 - lat1)
|
|
dLon = degreesToRadians(lon2 - lon1)
|
|
lat1 = degreesToRadians(lat1)
|
|
lat2 = degreesToRadians(lat2)
|
|
a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(
|
|
lat1
|
|
) * cos(lat2)
|
|
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
|
return int(earthRadiusKm * c)
|
|
|
|
@staticmethod
|
|
def heatmap_color_for(value):
|
|
r = 255
|
|
g = 255
|
|
if not value:
|
|
return "rgb(255,255,255)"
|
|
if value == 0:
|
|
return "rgb(255,255,255)"
|
|
if value <= 0.5:
|
|
g = 256
|
|
r = 2 * max(0, value) * 256
|
|
if value > 0.5:
|
|
g = 2 * (1 - min(1, value)) * 256
|
|
r = 256
|
|
return f"rgb({r},{g},{0})"
|
|
|
|
def groups_6_4(self):
|
|
"""
|
|
6 groups of 4 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((g, l))
|
|
homeGames[g, p].append((g, l))
|
|
awayGames[g, l].append((g, p))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_3_8(self):
|
|
"""
|
|
3 groups of 8 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
if g % 2 == 0:
|
|
other_group = self.groups[i - 1]
|
|
else:
|
|
other_group = self.groups[i + 1]
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((g, l))
|
|
opponents[g, p].append((other_group, l))
|
|
if p == "A" and l in ["B", "C", "D"]:
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, l].append((g, p))
|
|
homeGames[g, p].append((other_group, l))
|
|
awayGames[other_group, l].append((g, p))
|
|
if p == "B" and l in ["C", "D"]:
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, l].append((g, p))
|
|
homeGames[g, p].append((other_group, l))
|
|
awayGames[other_group, l].append((g, p))
|
|
if p == "C" and l in ["D"]:
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, l].append((g, p))
|
|
homeGames[g, p].append((other_group, l))
|
|
awayGames[other_group, l].append((g, p))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_3_8_stephan(self):
|
|
"""
|
|
3 groups of 8 teams - stephan
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
|
|
for i, g in enumerate(self.groups):
|
|
if g % 2 == 0:
|
|
other_group = self.groups[i - 1]
|
|
else:
|
|
other_group = self.groups[i + 1]
|
|
for i2, p in enumerate(self.pots):
|
|
other_pots = [k for k in self.pots]
|
|
for j2, l in enumerate(other_pots):
|
|
if p == l:
|
|
opponents[g, p].append((other_group, l))
|
|
elif i2 + j2 == 3:
|
|
opponents[g, p].append((g, l))
|
|
else:
|
|
opponents[g, p].append((g, l))
|
|
opponents[g, p].append((other_group, l))
|
|
|
|
if g % 2 == 0:
|
|
awayGames[g, "A"] += [(g, "D"), (g, "B"), (g, "C")]
|
|
homeGames[g, "A"] += [
|
|
(other_group, "A"),
|
|
(other_group, "B"),
|
|
(other_group, "C"),
|
|
]
|
|
|
|
awayGames[g, "B"] += [(other_group, "A"), (g, "C"), (g, "D")]
|
|
homeGames[g, "B"] += [(g, "A"), (other_group, "B"), (other_group, "D")]
|
|
|
|
awayGames[g, "C"] += [(other_group, "A"), (other_group, "C"), (g, "D")]
|
|
homeGames[g, "C"] += [(g, "B"), (other_group, "D"), (g, "A")]
|
|
|
|
awayGames[g, "D"] += [
|
|
(other_group, "D"),
|
|
(other_group, "C"),
|
|
(other_group, "B"),
|
|
]
|
|
homeGames[g, "D"] += [(g, "A"), (g, "B"), (g, "C")]
|
|
|
|
else:
|
|
awayGames[g, "A"] += [(other_group, "A"), (g, "B"), (g, "C")]
|
|
homeGames[g, "A"] += [(g, "D"), (other_group, "B"), (other_group, "C")]
|
|
|
|
awayGames[g, "B"] += [(other_group, "B"), (other_group, "A"), (g, "D")]
|
|
homeGames[g, "B"] += [(g, "A"), (g, "C"), (other_group, "D")]
|
|
|
|
awayGames[g, "C"] += [(g, "B"), (other_group, "A"), (g, "D")]
|
|
homeGames[g, "C"] += [(g, "A"), (other_group, "C"), (other_group, "D")]
|
|
|
|
awayGames[g, "D"] += [(g, "A"), (other_group, "C"), (other_group, "B")]
|
|
homeGames[g, "D"] += [(g, "B"), (g, "C"), (other_group, "D")]
|
|
|
|
# if p == 'A':
|
|
# if l == 'A':
|
|
# awayGames[g, p].append((g, l))
|
|
# if l in ['B','C']:
|
|
# awayGames[g, p].append((g, l))
|
|
# homeGames[g, l].append((g, p))
|
|
# homeGames[g, p].append((other_group, l))
|
|
# awayGames[other_group, l].append((g, p))
|
|
# if p == 'B' and l in ['C','D']:
|
|
# awayGames[g, p].append((g, l))
|
|
# homeGames[g, l].append((g, p))
|
|
# homeGames[g, p].append((other_group, l))
|
|
# awayGames[other_group, l].append((g, p))
|
|
# if p == 'C' and l in ['D']:
|
|
# awayGames[g, p].append((g, l))
|
|
# homeGames[g, l].append((g, p))
|
|
# homeGames[g, p].append((other_group, l))
|
|
# awayGames[other_group, l].append((g, p))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_2_12_martin(self):
|
|
"""
|
|
2 groups of 12 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
half = len(self.groups) // 2
|
|
if g <= half:
|
|
left_group = self.groups[:half][i - 1]
|
|
right_group = self.groups[:half][(i + 1) % half]
|
|
else:
|
|
left_group = self.groups[half:][(i - half - 1)]
|
|
right_group = self.groups[half:][(i - half + 1) % half]
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((right_group, l))
|
|
opponents[g, p].append((left_group, l))
|
|
homeGames[g, p].append((left_group, l))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_2_12_stephan(self):
|
|
"""
|
|
2 groups of 12 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
half = len(self.groups) // 2
|
|
if g <= half:
|
|
left_group = self.groups[:half][i - 1]
|
|
right_group = self.groups[:half][(i + 1) % half]
|
|
else:
|
|
left_group = self.groups[half:][(i - half - 1)]
|
|
right_group = self.groups[half:][(i - half + 1) % half]
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((g, l))
|
|
if p == "A" and l in ["B", "C"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "A" and l in ["D"]:
|
|
opponents[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
elif p == "B" and l in ["C", "D"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "B" and l in ["A"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
elif p == "C" and l in ["D"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "C" and l in ["A", "B"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
elif p == "D" and l in ["A"]:
|
|
opponents[g, p].append((right_group, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
elif p == "D" and l in ["B", "C"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_1_24_chess(self):
|
|
return self.groups_1_24()
|
|
|
|
def groups_1_24(self):
|
|
"""
|
|
1 groups of 24 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
left_group = self.groups[i - 1]
|
|
right_group = self.groups[(i + 1) % len(self.groups)]
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((right_group, l))
|
|
opponents[g, p].append((left_group, l))
|
|
homeGames[g, p].append((left_group, l))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def groups_1_24_stephan(self):
|
|
"""
|
|
1 groups of 24 teams
|
|
"""
|
|
opponents = defaultdict(lambda: [])
|
|
homeGames = defaultdict(lambda: [])
|
|
awayGames = defaultdict(lambda: [])
|
|
for i, g in enumerate(self.groups):
|
|
left_group = self.groups[i - 1]
|
|
right_group = self.groups[(i + 1) % len(self.groups)]
|
|
for p in self.pots:
|
|
other_pots = [k for k in self.pots if k != p]
|
|
for l in other_pots:
|
|
opponents[g, p].append((g, l))
|
|
if p == "A" and l in ["B", "C"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "A" and l in ["D"]:
|
|
opponents[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
elif p == "B" and l in ["C", "D"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "B" and l in ["A"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
elif p == "C" and l in ["D"]:
|
|
opponents[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
elif p == "C" and l in ["A", "B"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
elif p == "D" and l in ["A"]:
|
|
opponents[g, p].append((right_group, l))
|
|
homeGames[g, p].append((right_group, l))
|
|
awayGames[g, p].append((g, l))
|
|
elif p == "D" and l in ["B", "C"]:
|
|
opponents[g, p].append((left_group, l))
|
|
awayGames[g, p].append((left_group, l))
|
|
homeGames[g, p].append((g, l))
|
|
|
|
return opponents, homeGames, awayGames
|
|
|
|
def check_feasibility(self, fixed_groups, nSim):
|
|
|
|
model_time = time.time()
|
|
|
|
sol_dict = {g: {b: None for b in self.pots} for g in self.groups}
|
|
|
|
if self.algorithm == "SAT":
|
|
model_sat = cp_model.CpModel()
|
|
|
|
x_sat = {}
|
|
for g in self.groups:
|
|
for t in self.teams:
|
|
t_id = t["id"]
|
|
x_sat[t_id, g] = model_sat.NewBoolVar(f"var_{t_id}_{g}")
|
|
|
|
# one group for each team
|
|
for t in self.teams:
|
|
model_sat.AddExactlyOne(x_sat[t["id"], g] for g in self.groups)
|
|
|
|
# one team from each pot
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
model_sat.AddExactlyOne(
|
|
x_sat[t["id"], g] for t in self.teams if t["pot"] == p
|
|
)
|
|
|
|
# no country conflicts
|
|
for c in self.countries:
|
|
# print(c)
|
|
for i, t1 in enumerate(self.teams_by_country[c]):
|
|
for t2 in self.teams_by_country[c][i + 1 :]:
|
|
for (g1, p1), other_games in self.opponents.items():
|
|
if p1 == t1["pot"]:
|
|
for g2, p2 in other_games:
|
|
if p2 == t2["pot"]:
|
|
model_sat.AddAtMostOne(
|
|
x_sat[t1["id"], g1], x_sat[t2["id"], g2]
|
|
)
|
|
|
|
# add fixations
|
|
nFixed = 0
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
if fixed_groups[g][p]:
|
|
nFixed += 1
|
|
model_sat.Add(x_sat[fixed_groups[g][p]["id"], g] >= 1)
|
|
|
|
if self.algorithm == "MIP":
|
|
model_mip = LpProblem("Xpress", LpMinimize)
|
|
|
|
x_mip = {}
|
|
for g in self.groups:
|
|
for t in self.teams:
|
|
t_id = t["id"]
|
|
x_mip[t_id, g] = LpVariable(
|
|
f"var_{t_id}_{g}", lowBound=0, upBound=1, cat=LpContinuous
|
|
)
|
|
|
|
# one group for each team
|
|
for t in self.teams:
|
|
model_mip += lpSum([x_mip[t["id"], g] for g in self.groups]) == 1
|
|
|
|
# one team from each pot
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
model_mip += (
|
|
lpSum([x_mip[t["id"], g] for t in self.teams if t["pot"] == p])
|
|
== 1
|
|
)
|
|
|
|
# no country conflicts
|
|
for c in self.countries:
|
|
# print(c)
|
|
for i, t1 in enumerate(self.teams_by_country[c]):
|
|
for t2 in self.teams_by_country[c][i + 1 :]:
|
|
for (g1, p1), other_games in self.opponents.items():
|
|
if p1 == t1["pot"]:
|
|
for g2, p2 in other_games:
|
|
if p2 == t2["pot"]:
|
|
model_mip += (
|
|
x_mip[t1["id"], g1] + x_mip[t2["id"], g2]
|
|
<= 1
|
|
)
|
|
|
|
# add fixations
|
|
nFixed = 0
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
if fixed_groups[g][p]:
|
|
nFixed += 1
|
|
model_mip += x_mip[fixed_groups[g][p]["id"], g] >= 1
|
|
|
|
model_mip += lpSum([x_mip[key] for key in x_mip.keys()])
|
|
|
|
if self.algorithm == "XP":
|
|
model_xp = xp.problem(name="Xpress", sense=xp.minimize)
|
|
|
|
x_xp = {}
|
|
for g in self.groups:
|
|
for t in self.teams:
|
|
t_id = t["id"]
|
|
x_xp[t_id, g] = xp.var(ub=10, vartype=xp.integer)
|
|
|
|
model_xp.addVariable(x_xp)
|
|
|
|
# one group for each team
|
|
for t in self.teams:
|
|
model_xp.addConstraint(
|
|
xp.Sum([x_xp[t["id"], g] for g in self.groups]) == 1
|
|
)
|
|
|
|
# one team from each pot
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
model_xp.addConstraint(
|
|
xp.Sum([x_xp[t["id"], g] for t in self.teams if t["pot"] == p])
|
|
== 1
|
|
)
|
|
|
|
# no country conflicts
|
|
for c in self.countries:
|
|
for i, t1 in enumerate(self.teams_by_country[c]):
|
|
for t2 in self.teams_by_country[c][i + 1 :]:
|
|
for (g1, p1), other_games in self.opponents.items():
|
|
if p1 == t1["pot"]:
|
|
for g2, p2 in other_games:
|
|
if p2 == t2["pot"]:
|
|
model_xp.addConstraint(
|
|
x_xp[t1["id"], g1] + x_xp[t2["id"], g2] <= 1
|
|
)
|
|
|
|
# no more than 2 teams from same country in one group
|
|
# for c in self.countries:
|
|
# for g in self.groups:
|
|
# model_xp.addConstraint(
|
|
# xp.Sum(
|
|
# [x_xp[t["id"], g] for t in self.teams if t["country"] == c]
|
|
# )
|
|
# <= 2
|
|
# )
|
|
|
|
if self.chess:
|
|
# print("BLUE",self.blue_groups)
|
|
model_xp.addConstraint(
|
|
xp.Sum(x_xp[t, g] for t in self.red_teams for g in self.blue_groups)
|
|
<= 0
|
|
)
|
|
# print("RED",self.red_groups)
|
|
model_xp.addConstraint(
|
|
xp.Sum(x_xp[t, g] for t in self.blue_teams for g in self.red_groups)
|
|
<= 0
|
|
)
|
|
|
|
# do not play other countries more than 2 times
|
|
if self.opt_param == "max_2":
|
|
for t1 in self.teams:
|
|
for c in self.countries:
|
|
for (g1, p1), opponents in self.opponents.items():
|
|
if p1 == t1['pot']:
|
|
model_xp.addConstraint(
|
|
xp.Sum([x_xp[t2['id'], g2] for (g2, p2) in opponents for t2 in self.teams if p2 == t2['pot'] and t2['country'] == c]) <= 2)
|
|
|
|
|
|
# print(t1['name'],t1['country'],t1['pot'],[t2['name'] for (g2, p2) in awayGames for t2 in self.teams if p2 == t2['pot'] and t2['country'] == c])
|
|
# for (g2, p2) in awayGames:
|
|
# if p2 == t2['pot']:
|
|
# model_xp.addConstraint(
|
|
# x_xp[t1['id'], g1] + x_xp[t2['id'], g2] <= 1)
|
|
|
|
# # model_xp.addConstraint(
|
|
# xp.Sum([x_xp[t['id'], g] for t in self.teams if t['country'] == c]) <= 2)
|
|
# for t in self.teams:
|
|
# for c in ['Finland']:
|
|
# for t2 in self.teams_by_country[c]:
|
|
# for (g1, p1), awayGames in self.awayGames.items():
|
|
# if p1 == t1['pot']:
|
|
# for (g2, p2) in awayGames:
|
|
# if p2 == t2['pot']:
|
|
# print(t['name'],t['country'], t2['name'], t2['country'])
|
|
# model_xp.addConstraint(
|
|
# xp.Sum([x_xp[t2['id'], g] for (g2, p2) in awayGames]) <= 3)
|
|
|
|
# add fixations
|
|
nFixed = 0
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
if fixed_groups[g][p]:
|
|
nFixed += 1
|
|
model_xp.addConstraint(x_xp[fixed_groups[g][p]["id"], g] >= 1)
|
|
# print(f"\tFixed {fixed_groups[g][p]['name']}, {fixed_groups[g][p]['country']} in group {g}")
|
|
|
|
model_xp.setObjective(
|
|
xp.Sum([x_xp[key] for key in x_xp.keys()]), sense=xp.minimize
|
|
)
|
|
|
|
if self.algorithm == "SAT":
|
|
solver = cp_model.CpSolver()
|
|
start_time = time.time()
|
|
status = solver.Solve(model_sat)
|
|
comp_time = time.time() - start_time
|
|
model_time = time.time() - model_time - comp_time
|
|
# solver.parameters.enumerate_all_solutions = True
|
|
# solver.parameters.log_search_progress = True
|
|
|
|
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
|
|
if self.html_output:
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
for t in self.basepots[p]:
|
|
if solver.BooleanValue(x_sat[t["id"], g]):
|
|
sol_dict[g][p] = t
|
|
self.html_solution(nSim, sol_dict, fixed_groups)
|
|
return True, comp_time, model_time, sol_dict
|
|
else:
|
|
return False, comp_time, model_time, {}
|
|
elif self.algorithm == "MIP":
|
|
# with open ("model2_xpress.txt", "w") as f:
|
|
# f.write(model_mip.__repr__())
|
|
start_time = time.time()
|
|
model_mip.solve(PULP_CBC_CMD(msg=0))
|
|
comp_time = time.time() - start_time
|
|
model_time = time.time() - model_time - comp_time
|
|
|
|
if model_mip.status == 1:
|
|
if self.html_output:
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
for t in self.basepots[p]:
|
|
if x_mip[t["id"], g].value() > 0:
|
|
sol_dict[g][p] = t
|
|
self.html_solution(nSim, sol_dict, fixed_groups)
|
|
return True, comp_time, model_time, sol_dict
|
|
else:
|
|
return False, comp_time, model_time, {}
|
|
elif self.algorithm == "XP":
|
|
# with open ("model2_xpress.txt", "w") as f:
|
|
# f.write(model_mip.__repr__())
|
|
start_time = time.time()
|
|
model_xp.solve()
|
|
comp_time = time.time() - start_time
|
|
model_time = time.time() - model_time - comp_time
|
|
|
|
# print("STATUS",model_xp.getProbStatus(),model_xp.getProbStatusString())
|
|
|
|
if model_xp.getProbStatus() == 6:
|
|
if self.html_output:
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
for t in self.basepots[p]:
|
|
if model_xp.getSolution(x_xp[t["id"], g]) > 0:
|
|
sol_dict[g][p] = t
|
|
self.html_solution(nSim, sol_dict, fixed_groups)
|
|
|
|
return True, comp_time, model_time, sol_dict
|
|
|
|
else:
|
|
return False, comp_time, model_time, {}
|
|
|
|
def team_travel(self, team, sol):
|
|
|
|
return 0
|
|
|
|
def team_coefficients(self, team, sol):
|
|
return 0
|
|
|
|
def simulate(self, nTimes):
|
|
tt = time.time()
|
|
if nTimes < 1:
|
|
return None
|
|
|
|
tmp_stats = defaultdict(lambda: {})
|
|
|
|
for n in range(nTimes):
|
|
print(
|
|
f"{self.opponent_func.__name__} - {self.opt_param} - Simulation {n} - in {time.time()-tt}"
|
|
)
|
|
ttt = time.time()
|
|
|
|
sol_dict = {g: {b: None for b in self.pots} for g in self.groups}
|
|
|
|
pots = copy.deepcopy(self.basepots)
|
|
infeasible = False
|
|
conflicts = defaultdict(lambda: 0)
|
|
total_time = 0
|
|
total_model_time = 0
|
|
total_computations = 0
|
|
|
|
self.blue_groups = []
|
|
self.red_groups = []
|
|
|
|
feasible = False
|
|
for p in self.pots:
|
|
pot = pots[p]
|
|
random.shuffle(pot)
|
|
|
|
while pot:
|
|
r = random.choice(pot)
|
|
|
|
for g in self.groups:
|
|
if sol_dict[g][p]:
|
|
continue
|
|
else:
|
|
# print(f"Trying to add {r['name']} to group {g}")
|
|
sol_dict[g][p] = r
|
|
feasible, comptime, modeltime, _ = self.check_feasibility(
|
|
sol_dict, nSim=n
|
|
)
|
|
# print("\tFeasible:", feasible)
|
|
|
|
total_computations += 1
|
|
total_time += comptime
|
|
total_model_time += modeltime
|
|
if feasible:
|
|
feasible = True
|
|
if self.chess and not self.blue_groups:
|
|
if r["id"] in self.blue_teams:
|
|
self.blue_groups = (
|
|
[1, 3, 5] if g % 2 == 1 else [2, 4, 6]
|
|
)
|
|
self.red_groups = (
|
|
[2, 4, 6] if g % 2 == 1 else [1, 3, 5]
|
|
)
|
|
elif r["id"] in self.red_teams:
|
|
self.blue_groups = (
|
|
[2, 4, 6] if g % 2 == 1 else [1, 3, 5]
|
|
)
|
|
self.red_groups = (
|
|
[1, 3, 5] if g % 2 == 1 else [2, 4, 6]
|
|
)
|
|
break
|
|
else:
|
|
# print("\tCONFLICT: skipping group {} for team {}".format(g,r))
|
|
conflicts[p] += 1
|
|
sol_dict[g][p] = None
|
|
|
|
if not feasible:
|
|
infeasible = True
|
|
break
|
|
|
|
pot.remove(r)
|
|
|
|
travel = defaultdict(lambda: 0)
|
|
coefficients = defaultdict(lambda: 0)
|
|
visited_countries = defaultdict(lambda: set({}))
|
|
visited_finland = defaultdict(lambda: 0)
|
|
travel_finland = defaultdict(lambda: 0)
|
|
if not infeasible:
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
t1 = sol_dict[g][p]
|
|
for ag in self.awayGames[g, p]:
|
|
t2 = sol_dict[ag[0]][ag[1]]
|
|
travel[t1["id"]] += self.distance_matrix[t1["id"], t2["id"]]
|
|
if t2["country"] == "Switzerland":
|
|
travel_finland[t1["id"]] += 1
|
|
for op in self.opponents[g, p]:
|
|
t2 = sol_dict[op[0]][op[1]]
|
|
if self.opponent_func.__name__ == "groups_6_4":
|
|
coefficients[t1["id"]] += 2 * (
|
|
abs(t1["coeff"] - t2["coeff"])
|
|
)
|
|
else:
|
|
coefficients[t1["id"]] += abs(t1["coeff"] - t2["coeff"])
|
|
visited_countries[t1["id"]].add(t2["country"])
|
|
if t2["country"] == "Switzerland":
|
|
visited_finland[t1["id"]] += 1
|
|
else:
|
|
print("INFEASIBLE")
|
|
exit()
|
|
|
|
blockings, breaks = self.create_schedule(sol_dict, n)
|
|
# blockings = defaultdict(lambda:0)
|
|
# breaks = defaultdict(lambda:0)
|
|
|
|
tmp_stats[n] = {
|
|
"conflicts": conflicts,
|
|
"infeasible": infeasible,
|
|
"comptime": total_time,
|
|
"modeltime": total_model_time,
|
|
"total_computations": total_computations,
|
|
"travel": travel,
|
|
"coefficients": coefficients,
|
|
"visited_countries": {
|
|
t["id"]: len(visited_countries[t["id"]]) for t in self.teams
|
|
},
|
|
"blockings": blockings,
|
|
"breaks": breaks,
|
|
"visited_finland": visited_finland,
|
|
"travel_finland": travel_finland,
|
|
}
|
|
|
|
with open(f"json/{self.opponent_func.__name__}_{n}.json", "w") as f:
|
|
json.dump(tmp_stats, f, cls=NumpyEncoder)
|
|
|
|
nInfeasible = sum(s["infeasible"] for s in tmp_stats.values()) > 0
|
|
nComputation = sum(s["total_computations"] for s in tmp_stats.values())
|
|
tComputation = sum(s["comptime"] for s in tmp_stats.values())
|
|
conflicts_dict = {
|
|
p: round(sum(s["conflicts"][p] for s in tmp_stats.values()) / nTimes, 2)
|
|
for p in self.pots
|
|
}
|
|
conflicts_dict["total"] = round(sum(conflicts_dict[p] for p in self.pots), 2)
|
|
travel_stats = {
|
|
t["id"]: {
|
|
"mean": round(
|
|
np.mean([s["travel"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
"std": round(
|
|
np.std([s["travel"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
"var": round(
|
|
np.var([s["travel"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
travel_stats["total"] = {
|
|
"mean": round(
|
|
np.mean([travel_stats[t["id"]]["mean"] for t in self.teams]), 2
|
|
),
|
|
"std": round(
|
|
np.mean([travel_stats[t["id"]]["std"] for t in self.teams]), 2
|
|
),
|
|
"var": round(
|
|
np.mean([travel_stats[t["id"]]["var"] for t in self.teams]), 2
|
|
),
|
|
}
|
|
coefficient_stats = {
|
|
t["id"]: {
|
|
"mean": round(
|
|
np.mean([s["coefficients"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
"std": round(
|
|
np.std([s["coefficients"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
"var": round(
|
|
np.var([s["coefficients"][t["id"]] for s in tmp_stats.values()]), 2
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
coefficient_stats["total"] = {
|
|
"mean": round(
|
|
np.mean([coefficient_stats[t["id"]]["mean"] for t in self.teams]), 2
|
|
),
|
|
"std": round(
|
|
np.mean([coefficient_stats[t["id"]]["std"] for t in self.teams]), 2
|
|
),
|
|
"var": round(
|
|
np.mean([coefficient_stats[t["id"]]["var"] for t in self.teams]), 2
|
|
),
|
|
}
|
|
|
|
visited_countries = {
|
|
t["id"]: {
|
|
"mean": round(
|
|
np.mean(
|
|
[s["visited_countries"][t["id"]] for s in tmp_stats.values()]
|
|
),
|
|
2,
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
visited_countries["total"] = {
|
|
"mean": round(
|
|
np.mean([visited_countries[t["id"]]["mean"] for t in self.teams]), 2
|
|
),
|
|
}
|
|
|
|
visited_finland = {
|
|
t["id"]: {
|
|
"sum": np.sum(
|
|
[
|
|
1
|
|
for s in tmp_stats.values()
|
|
if s["visited_finland"][t["id"]] >= 3
|
|
]
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
visited_finland["total"] = {
|
|
"sum": np.sum([visited_finland[t["id"]]["sum"] for t in self.teams]),
|
|
}
|
|
|
|
travel_finland = {
|
|
t["id"]: {
|
|
"sum": np.sum(
|
|
[1 for s in tmp_stats.values() if s["travel_finland"][t["id"]] >= 3]
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
travel_finland["total"] = {
|
|
"sum": np.sum([travel_finland[t["id"]]["sum"] for t in self.teams]),
|
|
}
|
|
|
|
blockings = {
|
|
t["id"]: {
|
|
"mean": round(
|
|
np.mean([s["blockings"][t["id"]] for s in tmp_stats.values()]), 3
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
blockings["total"] = {
|
|
"sum": round(np.sum([blockings[t["id"]]["mean"] for t in self.teams]), 3),
|
|
}
|
|
|
|
breaks = {
|
|
t["id"]: {
|
|
"mean": round(
|
|
np.mean([s["breaks"][t["id"]] for s in tmp_stats.values()]) * 0.5, 3
|
|
),
|
|
}
|
|
for t in self.teams
|
|
}
|
|
breaks["total"] = {
|
|
"sum": round(np.sum([breaks[t["id"]]["mean"] for t in self.teams]), 3),
|
|
}
|
|
|
|
stats = {
|
|
"nInfeasible": nInfeasible,
|
|
"nComputation": nComputation,
|
|
"tComputation": tComputation,
|
|
"conflicts_dict": conflicts_dict,
|
|
"conflicts_dict": conflicts_dict,
|
|
"travel_stats": travel_stats,
|
|
"coefficient_stats": coefficient_stats,
|
|
"visited_countries": visited_countries,
|
|
"visited_finland": visited_finland,
|
|
"travel_finland": travel_finland,
|
|
"blockings": blockings,
|
|
"breaks": breaks,
|
|
}
|
|
|
|
return stats
|
|
|
|
def create_schedule(self, sol_dict, nSim):
|
|
|
|
# for g in self.groups:
|
|
# for p in self.pots:
|
|
# print(g,p,sol_dict[g][p]['name'],sol_dict[g][p]['country'])
|
|
# for game in self.homeGames[g, p]:
|
|
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
|
# for game in self.awayGames[g, p]:
|
|
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
|
base_scenario_id = 13020
|
|
base_scenario = Scenario.objects.get(id=base_scenario_id)
|
|
|
|
scenario = copy_scenario(
|
|
base_scenario, f" - {self.opponent_func.__name__} - {self.opt_param} - {nSim}"
|
|
)
|
|
# scenario.base_scenario = base_scenario
|
|
scenario.save()
|
|
|
|
GameRequirement.objects.filter(scenario=scenario).delete()
|
|
games = []
|
|
for g in self.groups:
|
|
for p in self.pots:
|
|
# print(g,p,sol_dict[g][p]['name'],sol_dict[g][p]['country'])
|
|
for game in self.homeGames[g, p]:
|
|
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
|
games.append(
|
|
GameRequirement(
|
|
number=1,
|
|
scenario=scenario,
|
|
team1=Team.objects.get(id=sol_dict[g][p]["id"]),
|
|
team2=Team.objects.get(id=sol_dict[game[0]][game[1]]["id"]),
|
|
)
|
|
)
|
|
# for game in self.awayGames[g, p]:
|
|
# print("\t",game[0],game[1],sol_dict[game[0]][game[1]])
|
|
# games.append(GameRequirement(number=1, scenario=scenario, team1=Team.objects.get(id=sol_dict[game[0]][game[1]]['id']), team2=Team.objects.get(id=sol_dict[g][p]['id'])))
|
|
GameRequirement.objects.bulk_create(games)
|
|
|
|
s2 = scenario.id
|
|
user_name = "md"
|
|
user_is_staff = True
|
|
runMode = "New"
|
|
localsearch_time = 0
|
|
RUN_ENV = "celery"
|
|
SOLVER = "xpress"
|
|
|
|
sol = optimize(
|
|
task=None,
|
|
s2=s2,
|
|
user_name=user_name,
|
|
user_is_staff=user_is_staff,
|
|
runMode=runMode,
|
|
localsearch_time=localsearch_time,
|
|
RUN_ENV=RUN_ENV,
|
|
solver=SOLVER,
|
|
)
|
|
|
|
kpis = Availabilities(scenario.id, showSolution=1)
|
|
|
|
blockings = defaultdict(lambda: 0)
|
|
breaks = defaultdict(lambda: 0)
|
|
for v in kpis["violations"]:
|
|
blockings[v[0].id] += 1
|
|
for b in kpis["missingBreaks"]:
|
|
breaks[b] += 1
|
|
|
|
return blockings, breaks
|
|
|
|
def html_solution(self, nSim, sol_dict, fixed_groups):
|
|
|
|
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 g in self.groups:
|
|
if g in self.blue_groups:
|
|
color = "blue"
|
|
elif g in self.red_groups:
|
|
color = "red"
|
|
else:
|
|
color = "white"
|
|
sol += f"<th style='background-color:{color}'>{g}</th>"
|
|
sol += "</tr>"
|
|
sol += "</thead>\n"
|
|
sol += "<tbody>\n"
|
|
nFixed = 0
|
|
for p in self.pots:
|
|
sol += f"<tr><td>{p}</td>"
|
|
for g in self.groups:
|
|
if fixed_groups[g][p]:
|
|
color = "lightgreen"
|
|
nFixed += 1
|
|
else:
|
|
color = "lightyellow"
|
|
if sol_dict[g][p]["id"] in self.blue_teams:
|
|
text_color = "blue"
|
|
elif sol_dict[g][p]["id"] in self.red_teams:
|
|
text_color = "red"
|
|
else:
|
|
text_color = "black"
|
|
tpot = sol_dict[g][p]["pot"]
|
|
tname = sol_dict[g][p]["name"]
|
|
tcountry = sol_dict[g][p]["country"]
|
|
sol += f"<td style='background-color:{color};color:{text_color}'>({tpot}){tname}({tcountry})</td>"
|
|
sol += "</tr>"
|
|
sol += "</tbody>\n"
|
|
sol += "</table>\n"
|
|
sol += "<br><br><br>\n"
|
|
|
|
for (g1, p1), other_games in self.opponents.items():
|
|
for g2, p2 in other_games:
|
|
tpot = sol_dict[g1][p1]["pot"]
|
|
tname = sol_dict[g1][p1]["name"]
|
|
tcountry = sol_dict[g1][p1]["country"]
|
|
sol += f"({tpot}){tname}({tcountry})"
|
|
sol += " vs "
|
|
tpot = sol_dict[g2][p2]["pot"]
|
|
tname = sol_dict[g2][p2]["name"]
|
|
tcountry = sol_dict[g2][p2]["country"]
|
|
sol += f"({tpot}){tname}({tcountry})"
|
|
sol += "<br>"
|
|
sol += "<br>"
|
|
sol += "<br>"
|
|
|
|
if nFixed == 24:
|
|
with open(
|
|
f"html/{self.algorithm}_{self.opponent_func.__name__}_{self.opt_param}_{nSim}_{nFixed}_{self.suffix}_sol.html",
|
|
"w",
|
|
) as f:
|
|
f.write(sol)
|
|
|
|
|
|
# %%
|
|
|
|
|
|
# simulator = Draw_Simulator(algorithm='XP', opponent_func = Draw_Simulator.groups_2_12_stephan, html_output=False)
|
|
# nSim = 10
|
|
|
|
|
|
# %%
|
|
|
|
funcs = [
|
|
# Draw_Simulator.groups_6_4,
|
|
# Draw_Simulator.groups_3_8,
|
|
(Draw_Simulator.groups_1_24, "free"),
|
|
(Draw_Simulator.groups_1_24_chess, "free"),
|
|
# (Draw_Simulator.groups_1_24, "max_2"),
|
|
# (Draw_Simulator.groups_1_24_chess, "max_2"),
|
|
# Draw_Simulator.groups_2_12_martin,
|
|
# Draw_Simulator.groups_2_12_stephan,
|
|
# Draw_Simulator.groups_1_24_stephan,
|
|
# Draw_Simulator.groups_3_8_stephan,
|
|
]
|
|
|
|
|
|
scenario_id = 13020
|
|
scenario = Scenario.objects.get(id=scenario_id)
|
|
# Scenario.objects.filter(base_scenario=scenario).delete()
|
|
|
|
Scenario.objects.filter(season=scenario.season).exclude(id=scenario_id).delete()
|
|
|
|
filename = "worst_case"
|
|
|
|
|
|
stats = {}
|
|
for (func,opt_param) in funcs:
|
|
if func == Draw_Simulator.groups_1_24_chess:
|
|
simulator = Draw_Simulator(
|
|
algorithm="XP",
|
|
opponent_func=func,
|
|
html_output=True,
|
|
use_db=True,
|
|
use_chess=True,
|
|
suffix=filename,
|
|
opt_param=opt_param,
|
|
scenario_id=scenario_id,
|
|
|
|
)
|
|
else:
|
|
simulator = Draw_Simulator(
|
|
algorithm="XP", opponent_func=func, html_output=True, use_db=True,
|
|
suffix=filename,
|
|
opt_param=opt_param,
|
|
scenario_id=scenario_id,
|
|
)
|
|
nSim = 100
|
|
stats[(func.__name__,opt_param)] = simulator.simulate(nSim)
|
|
|
|
|
|
# %%
|
|
|
|
sol = " \
|
|
<style> \
|
|
table, th, td { \
|
|
border: 1px solid black; \
|
|
border-collapse: collapse; \
|
|
text-align: center; \
|
|
min-width:50px; \
|
|
padding:5px; \
|
|
margin: 5px; \
|
|
} \
|
|
</style> \
|
|
"
|
|
sol += "<table style='border:1px solid black'>\n"
|
|
sol += "<thead>\n"
|
|
sol += f"<tr><td rowspan='4'>n={nSim}</td>"
|
|
sol += f"<td colspan='{len(simulator.pots)}'>Conflicts</td>"
|
|
sol += f"<td colspan='10' rowspan='2'>Total</td>"
|
|
sol += f"<td colspan='{8*len(simulator.teams)}'>Teams</td>"
|
|
sol += "</tr>"
|
|
sol += "<tr>"
|
|
for p in simulator.pots:
|
|
sol += f"<td rowspan='3'>{p}</td>"
|
|
for t in simulator.teams:
|
|
sol += f"<td colspan='9'>{t['name']} ({t['country']})</td>"
|
|
sol += "</tr>"
|
|
sol += "<tr>"
|
|
sol += "<td colspan='1' rowspan='2'>Cfl.</td>"
|
|
sol += "<td colspan='2'>Trav.</td>"
|
|
sol += "<td colspan='2'>Coe.</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Block</td>"
|
|
sol += "<td colspan='1' rowspan='2'>No Travel</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Countr.</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Play Switzerland 3x</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Travel Switzerland 3x</td>"
|
|
for t in simulator.teams:
|
|
sol += "<td colspan='2' rowspan='1'>Trav.</td>"
|
|
sol += "<td colspan='2' rowspan='1'>Coe.</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Block</td>"
|
|
sol += "<td colspan='1' rowspan='2'>No Travel</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Countr.</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Play Switzerland 3x</td>"
|
|
sol += "<td colspan='1' rowspan='2'>Travel Switzerland 3x</td>"
|
|
sol += "</tr>"
|
|
sol += "<tr>"
|
|
sol += "<td>M</td>"
|
|
sol += "<td>S</td>"
|
|
sol += "<td>M</td>"
|
|
sol += "<td>S</td>"
|
|
for t in simulator.teams:
|
|
sol += "<td>M</td>"
|
|
sol += "<td>S</td>"
|
|
sol += "<td>M</td>"
|
|
sol += "<td>S</td>"
|
|
sol += "</tr>"
|
|
sol += "</thead>\n"
|
|
sol += "<tbody>\n"
|
|
for (func,opt_param) in funcs:
|
|
sol += "<tr>"
|
|
sol += f"<td>{func.__name__} - {opt_param} </td>"
|
|
for p in simulator.pots:
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['conflicts_dict'][p]}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['conflicts_dict']['total']}</td>"
|
|
ttmean = stats[(func.__name__,opt_param)]["travel_stats"]["total"]["mean"]
|
|
ttstd = stats[(func.__name__,opt_param)]["travel_stats"]["total"]["std"]
|
|
ctmean = stats[(func.__name__,opt_param)]["coefficient_stats"]["total"]["mean"]
|
|
ctstd = stats[(func.__name__,opt_param)]["coefficient_stats"]["total"]["std"]
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['travel_stats']['total']['mean']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['travel_stats']['total']['std']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['coefficient_stats']['total']['mean']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['coefficient_stats']['total']['std']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['blockings']['total']['sum']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['breaks']['total']['sum']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['visited_countries']['total']['mean']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['visited_finland']['total']['sum']}</td>"
|
|
sol += f"<td>{stats[(func.__name__,opt_param)]['travel_finland']['total']['sum']}</td>"
|
|
for t in simulator.teams:
|
|
tmean = stats[(func.__name__,opt_param)]["travel_stats"][t["id"]]["mean"]
|
|
tstd = stats[(func.__name__,opt_param)]["travel_stats"][t["id"]]["std"]
|
|
cmean = stats[(func.__name__,opt_param)]["coefficient_stats"][t["id"]]["mean"]
|
|
cstd = stats[(func.__name__,opt_param)]["coefficient_stats"][t["id"]]["std"]
|
|
blmean = stats[(func.__name__,opt_param)]["blockings"][t["id"]]["mean"]
|
|
brmean = stats[(func.__name__,opt_param)]["breaks"][t["id"]]["mean"]
|
|
visited = stats[(func.__name__,opt_param)]["visited_countries"][t["id"]]["mean"]
|
|
visited_finland = stats[(func.__name__,opt_param)]["visited_finland"][t["id"]]["sum"]
|
|
travel_finland = stats[(func.__name__,opt_param)]["travel_finland"][t["id"]]["sum"]
|
|
color = Draw_Simulator.heatmap_color_for(abs(tmean - ttmean) / ttmean)
|
|
sol += f"<td style='background-color:{color}'>{tmean}</td>"
|
|
color = Draw_Simulator.heatmap_color_for(abs(tstd - ttstd) / ttstd)
|
|
sol += f"<td style='background-color:{color}'>{tstd}</td>"
|
|
color = Draw_Simulator.heatmap_color_for(abs(cmean - ctmean) / ctmean)
|
|
sol += f"<td style='background-color:{color}'>{cmean}</td>"
|
|
color = Draw_Simulator.heatmap_color_for(abs(cstd - ctstd) / ctstd)
|
|
sol += f"<td style='background-color:{color}'>{cstd}</td>"
|
|
sol += f"<td >{blmean}</td>"
|
|
sol += f"<td >{brmean}</td>"
|
|
sol += f"<td >{visited}</td>"
|
|
sol += f"<td >{visited_finland}</td>"
|
|
sol += f"<td >{travel_finland}</td>"
|
|
|
|
sol += "</tr>"
|
|
sol += "</tbody>\n"
|
|
sol += "</table>\n"
|
|
|
|
|
|
|
|
|
|
|
|
with open(f"stats_{filename}.html", "w") as f:
|
|
f.write(sol)
|
|
|
|
|
|
# %%
|
|
|
|
# %%
|
|
|
|
with open(f"color_{filename}.html", "w") as f:
|
|
table = f"<table><tr>"
|
|
for i in range(1, 11):
|
|
color = Draw_Simulator.heatmap_color_for(i / 10)
|
|
table += f"<td style='background-color:{color}'>{color}</td>"
|
|
|
|
table += f"</tr></table>"
|
|
f.write(table)
|
|
|
|
|
|
# %%
|