Refactorize debug and warning functions

add switches to control optimization
This commit is contained in:
Jean-Christophe Dubacq 2024-10-24 20:11:39 +02:00
parent 67bab0af54
commit 474d2dffbd

219
get.py
View File

@ -6,6 +6,7 @@ import csv
import json
import os
import pdb # used for debugging
import inspect # used for debugging
import random
import sys
@ -26,6 +27,33 @@ def die(msg: str, status=3):
sys.exit(status)
def debug(*args):
if not hasattr(debug, "counter"):
debug.counter = 1 # Initialize the counter if it doesn't exist
else:
debug.counter += 1
caller_frame = inspect.currentframe().f_back
where = str(caller_frame.f_lineno) + "@" + caller_frame.f_code.co_name
if len(args) > 0:
print(f"[DEBUG {debug.counter}:{where}] " + str(args[0]), args[1:])
else:
print(f"[DEBUG {debug.counter}:{where}] (no reason given)")
def warning(*args):
if len(args) > 0:
print("[WARNING] " + str(args[0]), args[1:])
else:
print("[WARNING] (no reason given)")
def info(*args):
if len(args) > 0:
print("[INFO] " + str(args[0]), args[1:])
else:
print("[INFO] (no reason given)")
load_dotenv(".env")
SCODOC_SERVER = os.environ.get("SCODOC_SERVER") or "http://localhost:5000"
@ -39,7 +67,7 @@ SCODOC_PASSWORD = os.environ.get("SCODOC_PASSWORD") or die(
API_URL = f"{SCODOC_SERVER}/ScoDoc/api"
# TODO : refactor globals
debug = True # Not used
DEBUG = True # Not used
BLOCKING = True # Die if csv is incorrect
# TODO : refactor / put globals in a class, eg Config
@ -47,7 +75,11 @@ depts = []
orderkey = ""
def blockordie(status=2):
def blockordie(reason: str = "", status: int = 2):
if reason:
print(reason)
else:
print("Blocking, no reason given")
if BLOCKING:
sys.exit(status)
@ -66,17 +98,52 @@ def cli_check():
parser = argparse.ArgumentParser(description="Process some departments.")
parser.add_argument("--techno", action="store_true", help="Enable TECHNO mode")
parser.add_argument("depts", nargs="+", help="List of departments")
parser.add_argument("depts", nargs="*", help="List of departments")
parser.add_argument(
"--base",
"-b",
type=int,
choices=range(2000, 2667),
choices=range(2000, 2067),
default=2021,
help="base year for the cohort (integer between 2000 and 2666)",
)
optimize_group = parser.add_mutually_exclusive_group()
optimize_group.add_argument(
"--reuse", action="store_true", help="Reuse mode, sets value to 0"
)
optimize_group.add_argument(
"--optimize",
type=str,
nargs="?",
const="100", # Default value if --optimize is used without specifying n
help="Optimize mode, takes an optional integer (default is 100, or 300 if no optimization option specified)",
)
optimize_group.add_argument(
"--restart",
type=str,
nargs="?",
const="300", # Default value if --restart is used without specifying n
help="Restart & Optimize mode, takes an optional integer (default is 300)",
)
args = parser.parse_args()
Options.restart = False
if args.reuse:
Options.optimize = 0
elif args.restart is not None:
Options.restart = True
try:
Options.optimize = -int(args.restart)
except (TypeError, ValueError):
Options.optimize = -300
if args.restart:
args.depts.insert(0, args.restart)
else:
try:
Options.optimize = int(args.optimize)
except (TypeError, ValueError):
Options.optimize = 300
if args.optimize:
args.depts.insert(0, args.optimize)
Options.base_year = args.base
Options.techno = args.techno
@ -129,6 +196,8 @@ def conf_value(xkey: str):
"year_separator": " ",
"rank_separator": "",
"diplome_separator": "",
"reuse": "yes",
"optimize": "yes",
}
if xkey in conf:
return conf[xkey]
@ -176,8 +245,7 @@ def read_theme():
if len(row) == 0:
continue
elif len(row[0]) == 0:
print("Wrong line in theme : " + str(row))
blockordie()
blockordie("Wrong line in theme : " + str(row))
elif row[0][0] == "#":
continue
else:
@ -210,8 +278,7 @@ def read_redirects():
if len(row) == 0:
continue
elif len(row[0]) == 0:
print("Wrong line in redirect : " + str(row))
blockordie()
blockordie("Wrong line in redirect : " + str(row))
elif row[0][0] == "#":
continue
else:
@ -227,7 +294,7 @@ token = None
def get_json(url: str, params=None):
print(f"Requesting {url}")
debug(f"Requesting {url}")
global token
if token == None:
url_token = f"{API_URL}/tokens"
@ -237,18 +304,19 @@ def get_json(url: str, params=None):
if response.status_code == 200:
token = response.json().get("token")
else:
print(
f"Erreur de récupération de token: {response.status_code} - {response.text}"
blockordie(
f"Erreur de récupération de token: {response.status_code} - {response.text}",
status=1,
)
sys.exit(1)
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
# Afficher la réponse JSON
return response.json()
else:
print(f"Erreur avec {url}: {response.status_code} - {response.text}")
sys.exit(1)
blockordie(
f"Erreur avec {url}: {response.status_code} - {response.text}", status=1
)
formsem_dept = {}
@ -337,6 +405,8 @@ def get_override(sem, xkey, default=None):
def nick_replace(
department, diplome, rank, modalite, parcours, nick, year=Options.base_year
):
if type(rank) != int:
rank = 0
if len(department) > 0:
nick = nick.replace(
"{department}", conf_value("department_separator") + department
@ -357,7 +427,7 @@ def nick_replace(
nick = nick.replace("{diplomenobut}", conf_value("diplome_separator") + diplome)
else:
nick = nick.replace("{diplomenobut}", "")
if len(str(rank)) > 0:
if rank > 0:
nick = nick.replace("{rank}", conf_value("rank_separator") + str(rank))
else:
nick = nick.replace("{rank}", "")
@ -424,7 +494,6 @@ def analyse_student(semobj, etud, univ_year=None):
modalite = None
for g in goal:
gg = g.split("=")
# print(f"Looking for {gg[0]} yielding {gg[1]} out of {groupes}")
if gg[0] in groups:
modalite = gg[1]
nick = conf_value("nick")
@ -523,11 +592,11 @@ def analyse_depts():
continue
if bucket in studentsummary["cursus"]:
semestreerreur = int(bucket) + 1
print(
warning(
f"// Élève {etudid} dans deux semestres à la fois : S{semestreerreur}, semestres {studentsummary['cursus'][bucket]} et {semid}"
)
if "dept" in studentsummary and studentsummary["dept"] != dept:
print(
warning(
f"// Élève ayant changé de département {dept},{studentsummary['dept']}"
)
# department, diplome, rank, modalite, parcours, nick = analyse_student(
@ -1044,7 +1113,8 @@ def crossweight(node_position, node_layer, edges):
return w
def genetic_optimize(node_position, node_layer, edges):
def genetic_optimize(node_position, node_layer, edges, loops=1):
debug(f"Begin genetic optimization with {loops} loops")
oldcandidates = []
l_indices = list(range(5))
lays = []
@ -1055,6 +1125,7 @@ def genetic_optimize(node_position, node_layer, edges):
for i in lays[index]:
randomness_l.append(index)
w = crossweight(node_position, node_layer, edges)
for i in range(20):
oldcandidates.append([node_position.copy(), w])
w = crossweight(node_position, node_layer, edges)
@ -1070,7 +1141,7 @@ def genetic_optimize(node_position, node_layer, edges):
k += 1
oldcandidates.append([n, w])
candidates = oldcandidates
for i in range(300):
for i in range(loops):
oldcandidates = candidates
oldcandidates.sort(key=lambda x: x[1])
candidates = oldcandidates[:30]
@ -1119,11 +1190,37 @@ def genetic_optimize(node_position, node_layer, edges):
b = lays[i].copy()
b.sort(key=lambda x: best[x])
orders.append(b)
print(orders)
print(candidates[0][1])
debug(orders)
debug(candidates[0][1])
return orders
def ordernodes(layers, orders, edges):
node_position = {}
node_layer = {}
newls = [[], [], [], [], []]
if orders != {}:
for i in range(len(newls)):
ls = newls[i]
for node in orders[i]:
if node in layers[i]:
ls.append(node)
for node in layers[i]:
if node not in ls:
ls.append(node)
for layer, layernodes in enumerate(newls):
for j, n in enumerate(layernodes):
node_position[n] = j
node_layer[n] = layer
else:
for layer, layernodes in enumerate(layers):
for j, n in enumerate(layernodes):
node_position[n] = j
node_layer[n] = layer
debug(crossweight(node_position, node_layer, edges))
return node_position, node_layer, newls
def printsvg():
padding = 4
unit_ratio = 96 / 72
@ -1164,64 +1261,31 @@ def printsvg():
else:
node_structure[startnode]["next"].append([endnode, weight])
edges.append([startnode, endnode, weight])
node_position = {}
node_layer = {}
layer_structure = [
{"olayer": []},
{"olayer": []},
{"olayer": []},
{"olayer": []},
{"olayer": []},
]
lastorders = read_conf("best-" + orderkey)
if lastorders != {}:
for i in range(5):
ls = layer_structure[i]
ord = lastorders[i]
for node in lastorders[i]:
if node in layers[i]:
ls["olayer"].append(node)
for node in layers[i]:
if node not in ls["olayer"]:
ls["olayer"].append(node)
for layer, layernodes in enumerate(layer_structure):
for j, n in enumerate(layernodes["olayer"]):
node_position[n] = j
node_layer[n] = layer
print(crossweight(node_position, node_layer, edges))
filename = "best-" + orderkey
if Options.restart:
try:
os.remove(filename)
except OSError:
pass
if Options.optimize >= 0:
lastorders = read_conf(filename)
else:
for layer, layernodes in enumerate(layers):
for j, n in enumerate(layernodes):
node_position[n] = j
node_layer[n] = layer
orders = genetic_optimize(node_position, node_layer, edges)
lastorders = {}
node_position, node_layer, newls = ordernodes(layers, lastorders, edges)
if Options.optimize != 0:
orders = genetic_optimize(
node_position, node_layer, edges, loops=abs(Options.optimize)
)
else:
orders = newls
write_conf("best-" + orderkey, orders)
layer_structure = [
{"olayer": []},
{"olayer": []},
{"olayer": []},
{"olayer": []},
{"olayer": []},
]
for i in range(5):
ls = layer_structure[i]
ord = orders[i]
for node in orders[i]:
if node in layers[i]:
ls["olayer"].append(node)
for node in layers[i]:
if node not in ls["olayer"]:
ls["olayer"].append(node)
for layer, layernodes in enumerate(layer_structure):
for j, n in enumerate(layernodes["olayer"]):
node_position[n] = j
node_layer[n] = layer
print(crossweight(node_position, node_layer, edges))
node_position, node_layer, newls = ordernodes(layers, orders, edges)
layer_structure = []
density = []
for i in range(5):
ls = layer_structure[i]
ls["num"] = len(ls["olayer"])
ls = {}
ls["olayer"] = newls[i]
ls["num"] = len(newls[i])
ls["inout"] = 0
for j in ls["olayer"]:
lhi = 0
@ -1239,6 +1303,7 @@ def printsvg():
print(json.dumps(layer_structure, indent=2))
print(json.dumps(node_structure, indent=2))
ls["inout"] += k["size"]
layer_structure.append(ls)
if height == 0:
minheight = 0
for i in range(5):