from pathlib import Path import csv,json,sys import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt ROOT=Path(__file__).resolve().parents[1] plt.rcParams.update({'font.size':9,'axes.spines.top':False,'axes.spines.right':False,'savefig.dpi':180}) out=ROOT/'figures_v3';out.mkdir(exist_ok=True) r=json.loads((ROOT/'results_v3/innovation_report.json').read_text()) rows=list(csv.DictReader((ROOT/'results_v3/innovation_raw.csv').open())) names={'epoch_eliminate':'Reset on geometry change','v2_guarded':'v2 contradiction guard','certificate_iid':'Certificates, iid draws','certificate_eliminate':'Certificates, elimination'} colors=['#a96633','#757c89','#4989a1','#116e58'] fig,axes=plt.subplots(1,2,figsize=(9.4,3.3)) for method,color in zip(names,colors): sub=[x for x in r['summary'] if x['method']==method] phases=list(r['protocol']['phases']) axes[0].plot(range(len(phases)),[x['expected_mse'] for x in sub],marker='o',label=names[method],color=color) axes[1].plot(range(len(phases)),[x['rays_per_receiver'] for x in sub],marker='o',color=color) for ax in axes: ax.set_xticks(range(7),['Cold','Warm','Revisit','Relight','Smooth','Jump','Return'],rotation=30,ha='right');ax.grid(alpha=.18) axes[0].set_yscale('log');axes[0].set_ylabel('Conditional expected linear RGB MSE');axes[1].set_ylabel('Physical queries / receiver / frame') handles,labels=axes[0].get_legend_handles_labels();fig.legend(handles,labels,loc='lower center',ncol=2,fontsize=7,frameon=False);fig.tight_layout(rect=[0,.14,1,1]) for ext in ('png','pdf'):fig.savefig(out/f'innovation_results.{ext}') plt.close(fig) fig,axes=plt.subplots(1,2,figsize=(9.4,3.1)) for method,color in zip(names,colors): frames=sorted(set(int(x['frame']) for x in rows)) mean=[np.mean([float(x['expected_mse']) for x in rows if x['method']==method and int(x['frame'])==f]) for f in frames] axes[0].plot(frames,mean,label=names[method],color=color) axes[0].set_yscale('log');axes[0].set_xlabel('Observed frame');axes[0].set_ylabel('Expected linear RGB MSE') for p in (40,56,64):axes[0].axvline(p,color='gray',lw=.6,ls='--') axes[0].text(41,.004,'Smooth',fontsize=8);axes[0].text(57,.004,'Jump',fontsize=8);axes[0].text(65,.004,'Return',fontsize=8) q=json.loads((ROOT/'results_v3/queries_report.json').read_text()) axes[1].barh(['Fresh shared visibility','Certificate reuse'],[q['shared_fresh_baseline_queries'],q['total_queries_including_initialization']],color=['#757c89','#116e58']) axes[1].set_xlabel('Physical queries, including certificate initialization');axes[1].ticklabel_format(style='sci',axis='x',scilimits=(6,6)) axes[1].text(q['total_queries_including_initialization']+30000,1,f"{100*q['amortized_query_reduction_vs_shared']:.1f}% fewer",va='center',fontsize=8) fig.tight_layout() for ext in ('png','pdf'):fig.savefig(out/f'innovation_dynamics.{ext}') plt.close(fig) data=np.load(ROOT/'results_v3/queries_frames.npz') fig,axes=plt.subplots(3,3,figsize=(9.4,4.8)) for i,t in enumerate((0.,.5,1.)): for j in range(3): im=data[f't{t}_appearance{j}'];axes[i,j].imshow(np.clip(im,0,1)**(1/2.2));axes[i,j].set_axis_off() axes[i,j].set_title(f'Known time {t:g}, appearance {j+1}',fontsize=8) fig.suptitle('One coarse world state: finer spatial queries, prescribed motion, three readouts',fontsize=10) fig.tight_layout() for ext in ('png','pdf'):fig.savefig(out/f'query_readouts.{ext}') plt.close(fig) print('Saved three scientific figures as PNG and PDF')