adaptiswarm-edge / experiments.py
rajvivan's picture
Upload experiments.py
993ea1e verified
Raw
History Blame Contribute Delete
4.19 kB
"""Parallel experiment driver. Produces results.json + convergence.png."""
import json, time, sys, os; import numpy as np
from multiprocessing import Pool, cpu_count
from scipy.stats import wilcoxon
import runner, convergence as cv
N_RUNS = int(sys.argv[1]) if len(sys.argv) > 1 else 30
N_STEPS = 15; ITERS = 40
TOPOS = [10, 25, 50]; LAMBDAS = [10, 50, 100, 200]
BASELINES = ["RoundRobin", "LeastConn", "ACO", "PSO", "WOA", "AdaptiSwarm"]
METRICS = ["latency_ms", "utilization", "energy", "jain", "A_deadline", "all_deadline", "conv_iter"]
def worker(args):
name, nn, lam, seed = args
return runner.run_episode(name, nn, lam, seed, n_steps=N_STEPS, iters=ITERS, probe_step=8)
def run_all(nn, lam, names, n_runs):
tasks = [(n, nn, lam, s) for s in range(n_runs) for n in names]
with Pool(processes=min(8, cpu_count())) as p:
results = p.map(worker, tasks)
out = {n: {k: [] for k in METRICS} for n in names}
for r, (n, _, _, _) in zip(results, tasks):
for k in METRICS: out[n][k].append(r[k])
return out
def mean_std(v):
a = np.array(v, dtype=float); return [float(a.mean()), float(a.std())]
t0 = time.time()
grid = {}
for nn in TOPOS:
grid[nn] = {}
for lam in LAMBDAS:
out = run_all(nn, lam, BASELINES, N_RUNS)
grid[nn][lam] = {m: {k: out[m][k] for k in METRICS} for m in BASELINES}
print(f"[grid {time.time()-t0:.0f}s] nodes={nn} lam={lam}", flush=True)
conv_methods = ["ACO", "PSO", "WOA", "AdaptiSwarm"]
conv_iters = {m: [] for m in conv_methods}; curve_acc = {m: [] for m in conv_methods}
for s in range(N_RUNS):
curves, cc, tgt = cv.run_curves(25, 100, seed=s, iters=ITERS, methods=conv_methods)
for m in conv_methods: conv_iters[m].append(cc[m]); curve_acc[m].append(curves[m])
conv_curve_mean = {m: np.mean(np.stack(curve_acc[m]), axis=0).tolist() for m in conv_methods}
abl_ep_names = ["Abl_ACOonly", "Abl_PSOrand", "Abl_PSOseed", "AdaptiSwarm"]
abl_cv_names = ["Abl_ACOonly", "Abl_PSOrand", "Abl_PSOseed", "AdaptiSwarm"]
abl_ep = {m: {k: [] for k in ["latency_ms","utilization","jain"]} for m in abl_ep_names}
abl_cv = {m: [] for m in abl_cv_names}
for s in range(N_RUNS):
for m in abl_ep_names:
r = runner.run_episode(m, 50, 200, seed=s, n_steps=N_STEPS, iters=ITERS, probe_step=8)
for k in abl_ep[m]: abl_ep[m][k].append(r[k])
_, cc, _ = cv.run_curves(50, 200, seed=s, iters=ITERS, methods=abl_cv_names)
for m in abl_cv_names: abl_cv[m].append(cc[m])
W = {}
for nn in TOPOS:
W[nn] = {}
for lam in LAMBDAS:
W[nn][lam] = {}
a_lat = np.array(grid[nn][lam]["AdaptiSwarm"]["latency_ms"])
for m in BASELINES:
if m == "AdaptiSwarm": continue
try: _, p = wilcoxon(a_lat, np.array(grid[nn][lam][m]["latency_ms"]))
except ValueError: p = float("nan")
W[nn][lam][m] = float(p)
S = {}
for nn in TOPOS:
S[nn] = {}
for lam in LAMBDAS:
S[nn][lam] = {m: {k: mean_std(grid[nn][lam][m][k]) for k in METRICS} for m in BASELINES}
out = dict(config=dict(n_runs=N_RUNS, n_steps=N_STEPS, iters=ITERS, topos=TOPOS, lambdas=LAMBDAS, baselines=BASELINES),
summary=S, wilcoxon=W,
convergence=dict(iters={m: mean_std(conv_iters[m]) for m in conv_methods}, curves=conv_curve_mean),
ablation=dict(episode={m: {k: mean_std(abl_ep[m][k]) for k in abl_ep[m]} for m in abl_ep},
convergence={m: mean_std(abl_cv[m]) for m in abl_cv}))
with open("results.json", "w") as f: json.dump(out, f, indent=2)
print(f"[json {time.time()-t0:.0f}s]", flush=True)
import matplotlib; matplotlib.use("Agg"); import matplotlib.pyplot as plt
plt.figure(figsize=(6, 4))
styles = {"ACO": "C0--", "PSO": "C1-.", "WOA": "C2:", "AdaptiSwarm": "C3-"}
for m in conv_methods:
plt.plot(range(1, ITERS+1), conv_curve_mean[m], styles[m], label=m, linewidth=1.8)
plt.xlabel("Iteration"); plt.ylabel("Best fitness $F(\\mathcal{A})$")
plt.title("Convergence (25-node, $\\lambda=100$ tasks/s)"); plt.legend()
plt.grid(True, alpha=0.3); plt.yscale("log"); plt.tight_layout()
plt.savefig("convergence.png", dpi=160)
print(f"[done {time.time()-t0:.0f}s]", flush=True)