UEFA NL
This commit is contained in:
parent
6d78eb36bd
commit
7946c0c3e1
2
.gitignore
vendored
2
.gitignore
vendored
@ -159,3 +159,5 @@ cython_debug/
|
|||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
solver/data/save_point/*
|
||||||
4
solver/data/computation/.gitignore
vendored
Normal file
4
solver/data/computation/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.txt
|
||||||
|
!.gitignore
|
||||||
|
pulp/*
|
||||||
|
log/*
|
||||||
169
solver/test_simulations.py
Normal file
169
solver/test_simulations.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
# %%
|
||||||
|
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")
|
||||||
|
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||||
|
|
||||||
|
from leagues import settings
|
||||||
|
# settings.DATABASES['default']['NAME'] = PROJECT_PATH+'/db.sqlite3'
|
||||||
|
settings.DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
|
||||||
|
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 *
|
||||||
|
import pulp
|
||||||
|
from pulp import lpSum, value, XPRESS, GUROBI, PULP_CBC_CMD
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
from qualifiers.models import *
|
||||||
|
from common.models import GlobalTeam, GlobalCountry
|
||||||
|
from scheduler.models import Season, Scenario, Team, DayObj, CountryClash, Country
|
||||||
|
|
||||||
|
from qualifiers.draws import groupTeams, optimize_inversions4
|
||||||
|
from scheduler.solver.tasks.optimize import optimize
|
||||||
|
from scheduler.solver.tasks.optimize_submodels import ueluecl24_basicmodell_v2
|
||||||
|
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import datetime
|
||||||
|
import traceback
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import functools
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
user_name = 'md'
|
||||||
|
user_is_staff = True
|
||||||
|
runMode = 'Improve'
|
||||||
|
localsearch_time = 0
|
||||||
|
RUN_ENV = 'local'
|
||||||
|
SOLVER = 'xpress'
|
||||||
|
|
||||||
|
|
||||||
|
class TimeoutError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def timeout_wrapper(seconds=10, error_message=os.strerror(errno.ETIME)):
|
||||||
|
def decorator(func):
|
||||||
|
def _handle_timeout(signum, frame):
|
||||||
|
raise TimeoutError(error_message)
|
||||||
|
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
signal.signal(signal.SIGALRM, _handle_timeout)
|
||||||
|
signal.alarm(seconds)
|
||||||
|
try:
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
finally:
|
||||||
|
signal.alarm(0)
|
||||||
|
return result
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@timeout_wrapper(120)
|
||||||
|
def run_scenario(scenario):
|
||||||
|
|
||||||
|
s2 = scenario.id
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
error_filename = f'errors_report_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.json'
|
||||||
|
filename = f'report_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.json'
|
||||||
|
with open(f'reports/{error_filename}', mode='w', encoding='utf-8') as f:
|
||||||
|
json.dump([], f)
|
||||||
|
with open(f'reports/{filename}', mode='w', encoding='utf-8') as f:
|
||||||
|
json.dump([], f)
|
||||||
|
|
||||||
|
seasons = Season.objects.filter(is_hidden=False)
|
||||||
|
|
||||||
|
for i,season in enumerate(seasons):
|
||||||
|
if len(season.users_customers()) <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for scenario in season.scenarios.filter(is_hidden=False):
|
||||||
|
|
||||||
|
try:
|
||||||
|
run_scenario(scenario)
|
||||||
|
|
||||||
|
report = {
|
||||||
|
'run_id': i,
|
||||||
|
'league': season.league.name,
|
||||||
|
'season': season.nicename,
|
||||||
|
'scenario': scenario.name,
|
||||||
|
'scenario_id': scenario.id,
|
||||||
|
'runMode': runMode,
|
||||||
|
'localsearch_time': localsearch_time,
|
||||||
|
'info': 'success',
|
||||||
|
'message': 'ALL GOOD :-)'
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
report = {
|
||||||
|
'run_id': i,
|
||||||
|
'league': season.league.name,
|
||||||
|
'season': season.nicename,
|
||||||
|
'scenario': scenario.name,
|
||||||
|
'scenario_id': scenario.id,
|
||||||
|
'runMode': runMode,
|
||||||
|
'localsearch_time': localsearch_time,
|
||||||
|
'info': 'error',
|
||||||
|
'exception': repr(e),
|
||||||
|
'exception_type':e.__class__.__name__,
|
||||||
|
'traceback': f"{traceback.format_exc()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
os.system("killall optimizer")
|
||||||
|
|
||||||
|
with open(f'reports/{error_filename}') as instancejson:
|
||||||
|
instance = json.load(instancejson)
|
||||||
|
instance.append(report)
|
||||||
|
with open(f'reports/{error_filename}', mode='w', encoding='utf-8') as instancejson:
|
||||||
|
json.dump(instance, instancejson, indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
with open(f'reports/{filename}') as instancejson:
|
||||||
|
instance = json.load(instancejson)
|
||||||
|
instance.append(report)
|
||||||
|
with open(f'reports/{filename}', mode='w', encoding='utf-8') as instancejson:
|
||||||
|
json.dump(instance, instancejson, indent=4)
|
||||||
|
|
||||||
|
|
||||||
258
uefa/nations_league/analytics.py
Normal file
258
uefa/nations_league/analytics.py
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
# %%
|
||||||
|
#PROJECT_PATH = '/home/md/Work/ligalytics/leagues_stable/'
|
||||||
|
PROJECT_PATH = '/home/django/leagues/'
|
||||||
|
|
||||||
|
import os, sys
|
||||||
|
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'
|
||||||
|
#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'] = {}
|
||||||
|
|
||||||
|
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'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import django
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from scheduler.models import *
|
||||||
|
import pulp
|
||||||
|
from pulp import lpSum, value, XPRESS, GUROBI, PULP_CBC_CMD
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
from qualifiers.models import *
|
||||||
|
from common.models import GlobalTeam, GlobalCountry
|
||||||
|
from common.functions import getRandomHexColor
|
||||||
|
from scheduler.models import Season, Scenario, Team, DayObj, CountryClash, Country
|
||||||
|
|
||||||
|
from qualifiers.draws import groupTeams, optimize_inversions4
|
||||||
|
from scheduler.solver.tasks.optimize import optimize
|
||||||
|
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import csv
|
||||||
|
import networkx as nx
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
# %%
|
||||||
|
|
||||||
|
|
||||||
|
scenario = Scenario.objects.get(id=9541)
|
||||||
|
season = scenario.season
|
||||||
|
|
||||||
|
teams = Team.objects.filter(season=season,active=True).order_by('pot')
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
nSimulations = season.scenarios.count()
|
||||||
|
|
||||||
|
|
||||||
|
teams_in_group_together = {
|
||||||
|
(t1,t2):0 for t1 in teams for t2 in teams
|
||||||
|
}
|
||||||
|
violated_wishes = defaultdict(lambda:{'violations':0,'comments':defaultdict(lambda:0)})
|
||||||
|
violated_blockings = defaultdict(lambda:{'violations':0,'comments':defaultdict(lambda:0)})
|
||||||
|
|
||||||
|
|
||||||
|
for scenario in season.scenarios.all():
|
||||||
|
for conference in Conference.objects.filter(scenario=scenario,display_group=True).order_by('name'):
|
||||||
|
for t1 in conference.teams.all():
|
||||||
|
for t2 in conference.teams.all():
|
||||||
|
if t1 != t2:
|
||||||
|
teams_in_group_together[(t1,t2)] += 1
|
||||||
|
for wish in EncWish.objects.filter(scenario=scenario).exclude(violation="").order_by('prio'):
|
||||||
|
violated_wishes[f"{wish.reason}"]['violations'] += 1
|
||||||
|
violated_wishes[f"{wish.reason}"]['comments'][wish.violation] += 1
|
||||||
|
for wish in HAWish.objects.filter(scenario=scenario).exclude(violation="").order_by('prio'):
|
||||||
|
violated_wishes[f"{wish.reason}"]['violations'] += 1
|
||||||
|
violated_wishes[f"{wish.reason}"]['comments'][wish.violation] += 1
|
||||||
|
for wish in Pairing.objects.filter(scenario=scenario).exclude(violation="").order_by('prio'):
|
||||||
|
violated_wishes[f"{wish.comment}"]['violations'] += 1
|
||||||
|
violated_wishes[f"{wish.comment}"]['comments'][wish.violation] += 1
|
||||||
|
for game in scenario.solutionlist():
|
||||||
|
blockings = Blocking.objects.filter(scenario=scenario,day__id=game[0]).filter(Q(team=game[1],type="Home") | Q(team=game[1],type="Away"))
|
||||||
|
if blockings:
|
||||||
|
for b in blockings:
|
||||||
|
violated_blockings[b.team]['violations'] += 1
|
||||||
|
violated_blockings[b.team]['comments'][f"{b.type} - {b.day}"] += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
minVal = 999999
|
||||||
|
maxVal = 0
|
||||||
|
|
||||||
|
for key, val in teams_in_group_together.items():
|
||||||
|
if val > 0 and val < minVal:
|
||||||
|
minVal = val
|
||||||
|
if val > maxVal:
|
||||||
|
maxVal = val
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
|
||||||
|
|
||||||
|
def heatmap_color_for(value):
|
||||||
|
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 percentage(value):
|
||||||
|
return f"{round(value/max(nSimulations,1)*100)}%"
|
||||||
|
|
||||||
|
sol = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
|
||||||
|
sol += " \
|
||||||
|
<style> \
|
||||||
|
table, th, td { \
|
||||||
|
border: 1px solid black; \
|
||||||
|
border-collapse: collapse; \
|
||||||
|
text-align: center; \
|
||||||
|
min-width:40px; \
|
||||||
|
padding:3px; \
|
||||||
|
margin: 3px; \
|
||||||
|
font-family : Arial;\
|
||||||
|
} \
|
||||||
|
h1 {\
|
||||||
|
font-family : Arial;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
#etable td:nth-child(15),#etable th:nth-child(15) { border-right: 5px solid black; }\
|
||||||
|
#etable td:nth-child(31),#etable th:nth-child(31) { border-right: 5px solid black; }\
|
||||||
|
#etable td:nth-child(43),#etable th:nth-child(43) { border-right: 5px solid black; }\
|
||||||
|
tr:nth-child(14) { border-bottom: 5px solid black; }\
|
||||||
|
tr:nth-child(30) { border-bottom: 5px solid black; }\
|
||||||
|
tr:nth-child(42) { border-bottom: 5px solid black; }\
|
||||||
|
</style> \
|
||||||
|
"
|
||||||
|
sol += "</head><body>"
|
||||||
|
sol += "<h2>Probabilities of games</h2>"
|
||||||
|
sol += "<table id='etable' style='border:5px solid black'>\n"
|
||||||
|
sol += "<thead>\n"
|
||||||
|
sol += "<tr>"
|
||||||
|
sol += f"<th>{nSimulations}</th>"
|
||||||
|
sol += "<th colspan=14 style='border-right: 5px solid black;'>Pot A</th>"
|
||||||
|
sol += "<th colspan=16 style='border-right: 5px solid black;'>Pot B</th>"
|
||||||
|
sol += "<th colspan=12 style='border-right: 5px solid black;'>Pot C</th>"
|
||||||
|
sol += "<th colspan=12>Pot D</th>"
|
||||||
|
sol += "</tr>"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
sol += f"<th></th>\n"
|
||||||
|
for t in teams:
|
||||||
|
sol += f"<th>{t.shortname}</th>\n"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "</thead>\n"
|
||||||
|
sol += "<tbody>\n"
|
||||||
|
for t1 in teams:
|
||||||
|
sol += "<tr>\n"
|
||||||
|
sol += f"<td>{t1.shortname}</td>"
|
||||||
|
for t2 in teams:
|
||||||
|
color = heatmap_color_for((teams_in_group_together[(t1,t2)]-minVal)/((maxVal-minVal) or 1))
|
||||||
|
if teams_in_group_together[(t1,t2)] == 0:
|
||||||
|
color = 'grey'
|
||||||
|
val = f"{percentage(teams_in_group_together[(t1,t2)])}"
|
||||||
|
sol += f"<td style='background-color:{color}'>{val}</td>"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
|
||||||
|
sol += "</tbody>\n"
|
||||||
|
sol += "</table>\n"
|
||||||
|
|
||||||
|
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<hr>"
|
||||||
|
|
||||||
|
sol += "<h2>Availabilities</h2>"
|
||||||
|
sol += "<table id='etable' style='border:5px solid black'>\n"
|
||||||
|
sol += "<thead>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for t in violated_blockings.keys():
|
||||||
|
sol += f"<th >{t.shortname}</th>\n"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "</thead>\n"
|
||||||
|
sol += "<tbody>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for val in violated_blockings.values():
|
||||||
|
sol += f"<td >{val['violations']} ({percentage(val['violations'])})</td>"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for val in violated_blockings.values():
|
||||||
|
sol += f"<td>"
|
||||||
|
for c,n in val['comments'].items():
|
||||||
|
sol += f"{c}<br>"
|
||||||
|
sol += f"</td>"
|
||||||
|
sol += f"<td>"
|
||||||
|
for c,n in val['comments'].items():
|
||||||
|
sol += f"{n} ({percentage(n)})<br>"
|
||||||
|
sol += f"</td>"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "</tbody>\n"
|
||||||
|
sol += "</table>\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<br>"
|
||||||
|
sol += "<hr>"
|
||||||
|
|
||||||
|
sol += "<h2>Wishes</h2>"
|
||||||
|
sol += "<table id='etable' style='border:5px solid black'>\n"
|
||||||
|
sol += "<thead>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for t in violated_wishes.keys():
|
||||||
|
sol += f"<th >{t}</th>\n"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "</thead>\n"
|
||||||
|
sol += "<tbody>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for val in violated_wishes.values():
|
||||||
|
sol += f"<td >{val['violations']} ({percentage(val['violations'])})</td>"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "<tr>\n"
|
||||||
|
for val in violated_wishes.values():
|
||||||
|
sol += f"<td>"
|
||||||
|
for c,n in val['comments'].items():
|
||||||
|
sol += f"<table style='align:top;border:3px solid white'><tr><td style='width:100%'>{c}</td><td style='text-align: right'>{n} ({percentage(n)})</td></tr></table>"
|
||||||
|
sol += f"</td>"
|
||||||
|
sol += "</tr>\n"
|
||||||
|
sol += "</tbody>\n"
|
||||||
|
sol += "</table>\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
with open(f'analytics.html', 'w') as f:
|
||||||
|
f.write(sol)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user