repro-compact-conformal-subgraphs / sequence_timing.py
ProCreations's picture
Claim 3: whole nested sequence via parametric max-flow (certified 150/150 vs 2^n enumeration), with measured running time swept over m+n and gamma.
a07f822 verified
Raw
History Blame Contribute Delete
3.31 kB
"""Measured running time of the whole-sequence computation vs (m+n) and vs gamma."""
import time, json, sys, numpy as np
sys.setrecursionlimit(100000)
from cc_flow import sequence, rand_hg
def run(n,m,rng,reps=3):
ts=[];fl=[];op=[];gm=[]
for _ in range(reps):
E,w=rand_hg(rng,n,m); st={"flows":0,"ops":0}
t0=time.perf_counter(); seq=sequence(n,E,w,st); el=time.perf_counter()-t0
ts.append(el); fl.append(st["flows"]); op.append(st["ops"]); gm.append(len(seq))
return dict(n=n,m=m,mn=m+n,time=float(np.mean(ts)),flows=float(np.mean(fl)),
ops=float(np.mean(op)),gamma=float(np.mean(gm)))
def fit(x,y): return float(np.polyfit(np.log(x),np.log(y),1)[0])
if __name__=="__main__":
rng=np.random.default_rng(11); R={}
# (A) scale (m+n) with m ~ n
rows=[]
for n in (20,40,80,160,320,640):
rows.append(run(n,2*n,rng)); r=rows[-1]
print(" n=%4d m=%4d m+n=%5d gamma=%5.1f flows=%6.1f time=%8.3fs ops=%.3g"
%(r["n"],r["m"],r["mn"],r["gamma"],r["flows"],r["time"],r["ops"]),flush=True)
mn=[r["mn"] for r in rows]
R["size_sweep"]={"rows":rows,
"time_exponent_in_m_plus_n":round(fit(mn,[r["time"] for r in rows]),3),
"ops_exponent_in_m_plus_n":round(fit(mn,[r["ops"] for r in rows]),3),
"time_per_gamma_exponent":round(fit(mn,[r["time"]/r["gamma"] for r in rows]),3),
"ops_per_gamma_exponent":round(fit(mn,[r["ops"]/r["gamma"] for r in rows]),3),
"corollary1_exponent":2}
print(" [A] time ~ (m+n)^%.3f | ops ~ (m+n)^%.3f | time/gamma ~ (m+n)^%.3f | ops/gamma ~ (m+n)^%.3f (Corollary 1: 2)"
%(R["size_sweep"]["time_exponent_in_m_plus_n"],R["size_sweep"]["ops_exponent_in_m_plus_n"],
R["size_sweep"]["time_per_gamma_exponent"],R["size_sweep"]["ops_per_gamma_exponent"]),flush=True)
# (B) linearity in gamma at fixed size: vary edge density to move gamma
rows2=[]
for m in (10,20,40,80,160,320):
rows2.append(run(200,m,rng)); r=rows2[-1]
print(" n=200 m=%4d gamma=%5.1f flows=%6.1f time=%8.3fs"%(r["m"],r["gamma"],r["flows"],r["time"]),flush=True)
R["gamma_sweep"]={"rows":rows2,
"flows_per_gamma":[round(r["flows"]/max(r["gamma"],1),3) for r in rows2],
"time_exponent_in_gamma":round(fit([r["gamma"] for r in rows2],[r["time"] for r in rows2]),3),
"flows_exponent_in_gamma":round(fit([r["gamma"] for r in rows2],[r["flows"] for r in rows2]),3),
"corollary1_exponent":1}
print(" [B] time ~ gamma^%.3f | mincut calls ~ gamma^%.3f | calls/gamma %s (Corollary 1: 1)"
%(R["gamma_sweep"]["time_exponent_in_gamma"],R["gamma_sweep"]["flows_exponent_in_gamma"],
R["gamma_sweep"]["flows_per_gamma"]),flush=True)
# (C) reach beyond enumeration
E,w=rand_hg(rng,1200,2400); st={"flows":0,"ops":0}
t0=time.perf_counter(); seq=sequence(1200,E,w,st); el=time.perf_counter()-t0
R["reach"]={"n":1200,"m":2400,"gamma":len(seq),"flows":st["flows"],"time_s":round(el,2),
"brute_force_masks":"2^1200"}
print(" [C] n=1200 m=2400 solved in %.2fs with %d min-cuts, gamma=%d (enumeration would need 2^1200 masks)"
%(el,st["flows"],len(seq)),flush=True)
json.dump(R,open("cc_scale.json","w"),indent=1); print("DONE")