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