| """Generate LaTeX tables + numeric macros from results.json.""" |
| import json, os, numpy as np |
|
|
| R = json.load(open("results.json")) |
| OUT = "/app/paper"; os.makedirs(OUT, exist_ok=True) |
| S = R["summary"] |
| TOPOS = R["config"]["topos"]; LAMS = R["config"]["lambdas"] |
| NR = R["config"]["n_runs"] |
| METHODS = R["config"]["baselines"] |
| PRETTY = {"RoundRobin": "Round Robin", "LeastConn": "Least Conn.", |
| "ACO": "ACO", "PSO": "PSO", "WOA": "WOA", |
| "AdaptiSwarm": "\\textbf{AdaptiSwarm}"} |
| def g(nn, lam, m, metric): return S[str(nn)][str(lam)][m][metric] |
| def fmt(v, d=2): return f"{v:.{d}f}" |
| def best_mask(nn, lam, metric, lower_better=True): |
| vals = {m: g(nn, lam, m, metric)[0] for m in METHODS} |
| bv = min(vals.values()) if lower_better else max(vals.values()) |
| return {m: (abs(vals[m] - bv) < 1e-9) for m in METHODS} |
| def make_table(metric, caption, label, d=2, lower_better=True, mult=1.0): |
| l = []; l.append("\\begin{table}[t]"); l.append("\\centering") |
| l.append(f"\\caption{{{caption}}}"); l.append(f"\\label{{{label}}}") |
| l.append("\\setlength{\\tabcolsep}{3pt}"); l.append("\\footnotesize") |
| l.append("\\begin{tabular}{ll" + "c" * len(LAMS) + "}"); l.append("\\toprule") |
| l.append("Nodes & Method & " + " & ".join([f"$\\lambda{{=}}{x}$" for x in LAMS]) + " \\\\") |
| l.append("\\midrule") |
| for ti, nn in enumerate(TOPOS): |
| for mi, m in enumerate(METHODS): |
| row = [] |
| nc = f"\\multirow{{{len(METHODS)}}}{{*}}{{{nn}}}" if mi == 0 else "" |
| row.append(nc); row.append(PRETTY[m]) |
| for lam in LAMS: |
| bm = best_mask(nn, lam, metric, lower_better) |
| mean, std = g(nn, lam, m, metric) |
| cell = f"{fmt(mean*mult, d)}" |
| if bm[m]: cell = "\\underline{" + cell + "}" |
| row.append(cell) |
| l.append(" & ".join(row) + " \\\\") |
| if ti != len(TOPOS) - 1: l.append("\\midrule") |
| l.append("\\bottomrule"); l.append("\\end{tabular}"); l.append("\\end{table}") |
| return "\n".join(l) |
| with open(os.path.join(OUT, "table_latency.tex"), "w") as f: f.write(make_table("latency_ms", f"Avg Task Latency (ms), {NR} runs.", "tab:latency", d=2)) |
| with open(os.path.join(OUT, "table_util.tex"), "w") as f: f.write(make_table("utilization", f"Mean Utilization (\\%), {NR} runs.", "tab:util", d=1, lower_better=False)) |
| with open(os.path.join(OUT, "table_energy.tex"), "w") as f: f.write(make_table("energy", f"Energy (J/step), {NR} runs.", "tab:energy", d=2)) |
| with open(os.path.join(OUT, "table_conv.tex"), "w") as f: f.write(make_table("A_deadline", f"Class A Deadline Met (\\%), {NR} runs.", "tab:conv", d=1, lower_better=False)) |
| with open(os.path.join(OUT, "table_jain.tex"), "w") as f: f.write(make_table("jain", f"Jain Fairness Index, {NR} runs.", "tab:jain", d=3, lower_better=False)) |
| abl = R["ablation"] |
| abl_pretty = {"Abl_ACOonly": "V1: ACO only", "Abl_PSOrand": "V2: PSO (random)", "Abl_PSOseed": "V3: ACO-seeded PSO", "AdaptiSwarm": "\\textbf{Full}"} |
| order = ["Abl_ACOonly", "Abl_PSOrand", "Abl_PSOseed", "AdaptiSwarm"] |
| al = []; al.append("\\begin{table}[t]"); al.append("\\centering") |
| al.append(f"\\caption{{Ablation, {TOPOS[-1]}-node $\\lambda=200$, {NR} runs.}}") |
| al.append("\\label{tab:ablation}"); al.append("\\footnotesize") |
| al.append("\\setlength{\\tabcolsep}{4pt}"); al.append("\\begin{tabular}{lccc}") |
| al.append("\\toprule"); al.append("Variant & Latency (ms) & Util. (\\%) & Conv. iters \\\\"); al.append("\\midrule") |
| for m in order: |
| lat = abl["episode"][m]["latency_ms"]; util = abl["episode"][m]["utilization"]; conv = abl["convergence"][m] |
| al.append(f"{abl_pretty[m]} & {lat[0]:.2f}$\\pm${lat[1]:.2f} & {util[0]:.1f}$\\pm${util[1]:.1f} & {conv[0]:.1f}$\\pm${conv[1]:.1f} \\\\") |
| al.append("\\bottomrule"); al.append("\\end{tabular}"); al.append("\\end{table}") |
| with open(os.path.join(OUT, "table_ablation.tex"), "w") as f: f.write("\n".join(al)) |
| def avg_gain(metric, ref, lower_better=True, regimes=None): |
| if regimes is None: regimes = [(25,100),(25,200),(50,100),(50,200)] |
| gs = [] |
| for nn, lam in regimes: |
| a = g(nn, lam, "AdaptiSwarm", metric)[0]; b = g(nn, lam, ref, metric)[0] |
| if b == 0: continue |
| gs.append((1 - a/b)*100 if lower_better else (a/b - 1)*100) |
| return float(np.mean(gs)) if gs else 0.0 |
| nn_l, lam_l = TOPOS[-1], LAMS[-1] |
| lat_gain = avg_gain("latency_ms", "PSO", True) |
| en_gain = avg_gain("energy", "PSO", True) |
| lat_gain_aco = (1 - g(nn_l, lam_l, "AdaptiSwarm", "latency_ms")[0] / g(nn_l, lam_l, "ACO", "latency_ms")[0]) * 100 |
| qos_gain = g(nn_l, lam_l, "AdaptiSwarm", "A_deadline")[0] - g(nn_l, lam_l, "RoundRobin", "A_deadline")[0] |
| conv = R["convergence"]["iters"]; conv_gain = (1 - conv["AdaptiSwarm"][0] / conv["PSO"][0]) * 100 |
| jain_gain = (g(nn_l, lam_l, "AdaptiSwarm", "jain")[0] / g(nn_l, lam_l, "PSO", "jain")[0] - 1) * 100 |
| macros = [] |
| def mac(name, val): macros.append(f"\\newcommand{{\\{name}}}{{{val}}}") |
| mac("nRuns", NR); mac("nodesList", "$"+"$, $".join(str(t) for t in TOPOS)+"$") |
| mac("nodesSmall", TOPOS[0]); mac("nodesMedium", TOPOS[1]); mac("nodesLarge", TOPOS[2]) |
| mac("weightAlpha", "0.5"); mac("weightBeta", "0.3"); mac("weightGamma", "0.2") |
| mac("latGainMax", f"{lat_gain:.0f}\\%"); mac("energyGainMax", f"{en_gain:.0f}\\%") |
| mac("convGain", f"{conv_gain:.0f}\\%"); mac("latGainACO", f"{lat_gain_aco:.0f}\\%") |
| mac("qosGain", f"{qos_gain:.0f} pp"); mac("jainGain", f"{jain_gain:.0f}\\%") |
| with open(os.path.join(OUT, "numbers.tex"), "w") as f: f.write("\n".join(macros) + "\n") |
| print("Done.", flush=True) |
|
|