File size: 10,271 Bytes
9d6c005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""Ray-matched causal persistence benchmark; no ground-truth policy access."""
from pathlib import Path
import argparse,csv,json,time,platform,sys
ROOT=Path(__file__).resolve().parents[1]
sys.path.insert(0,str(ROOT))
import numpy as np
from aureole import WorldMemory,freeze,draw,correct,exact_mse
from aureole.core import proposal_from_bound
from aureole.renderer import Scene,VisibilityPrior,receiver_grid,light_grid,unoccluded,physical_table


def cluster_interval(values,seed=992):
    """95% percentile interval over independent scenes, not individual pixels."""
    x=np.asarray(values,float)
    rng=np.random.default_rng(seed)
    means=x[rng.integers(0,len(x),(10000,len(x)))].mean(1)
    return [float(v) for v in np.percentile(means,[2.5,97.5])]


def run(followup=False,output="reproduced_results"):
    config=json.loads((ROOT/("experiments_followup.json" if followup else "experiments.json")).read_text())
    prefix="followup" if followup else "rendering"
    points=receiver_grid(*config["receiver_grid"]);lights=light_grid(config["emitter_grid_side"])
    height,width=config["receiver_grid"]; vh,vw=config["viewport"]
    methods=config["methods"];prior=VisibilityPrior(ROOT/"models/visibility_prior.npz")
    phase_frames=[(phase,i) for phase,n in config["phases"].items() for i in range(n)]
    rows=[];prep=[];snapshots={};start=time.perf_counter();n=config["rays_per_receiver_per_frame"]
    for scene_id in config["scene_ids"]:
        scene=Scene.create(scene_id);changed=scene.changed()
        tic=time.perf_counter();features=scene.features(points[:,None,:],lights[None,:,:]);p_all=prior(features)
        prior_seconds=time.perf_counter()-tic
        bound0=unoccluded(points,lights);bound1=unoccluded(points,lights,True,0.7)
        # Privileged reference is used ONLY after the physical online estimate.
        truth0=physical_table(scene,points,lights,bound0)
        truth1=physical_table(scene,points,lights,bound1)
        truth2=physical_table(changed,points,lights,bound1)
        prep.append({"scene":scene_id,"prior_all_receivers_seconds":prior_seconds,"prior_receiver_emitter_pairs":len(points)*len(lights)})
        for seed in config["replicate_seeds"]:
            memory={method:WorldMemory(len(points),len(lights),f"scene-{scene_id}") for method in methods}
            rngs={method:np.random.default_rng(seed+scene_id*1000) for method in methods}
            for frame,(phase,phase_frame) in enumerate(phase_frames):
                if phase=="revisit" and phase_frame==0:
                    for m in memory.values():m.advance(config["unseen_ticks_before_revisit"])
                    memory["screen_cv"].retain_only(np.array([],dtype=int))
                x0=2+(phase_frame%4);y0=8
                ids=(np.arange(y0,y0+vh)[:,None]*width+np.arange(x0,x0+vw)[None,:]).ravel()
                b=(bound1 if phase in ("relight","hidden_change") else bound0)[ids]
                current_scene=changed if phase=="hidden_change" else scene
                offline_truth=(truth2 if phase=="hidden_change" else truth1 if phase=="relight" else truth0)[ids]
                target=offline_truth.sum(1)
                for method in methods:
                    tic=time.perf_counter();m=memory[method]
                    if method=="screen_cv":m.retain_only(ids)
                    base_prior=np.full((len(ids),len(lights)),0.5) if method=="constant_world_cv" else p_all[ids]
                    if method=="raw_importance":v=np.zeros_like(base_prior)
                    elif method=="neural_cv":v=base_prior
                    else:v=m.predict(ids,base_prior)
                    q=proposal_from_bound(b,v,m.trusted(ids),active=(method in ("world_active_cv","world_guarded_cv")))
                    snapshot=freeze(b*v[...,None],q)
                    j=draw(snapshot,n,rngs[method])
                    observed_visibility=current_scene.visibility(points[ids,None,:],lights[j])
                    physical=b[np.arange(len(ids))[:,None],j]*observed_visibility[...,None]
                    result=correct(snapshot,j,physical)
                    if method=="world_plugin":result=snapshot.integral.copy()
                    conflicts=0
                    if method not in ("raw_importance","neural_cv"):
                        conflicts=m.commit(ids,j,observed_visibility,revise_on_conflict=(method=="world_guarded_cv"))
                    m.advance()
                    runtime=time.perf_counter()-tic
                    # Oracle enumeration is outside the online policy and timing.
                    conditional=(np.mean((snapshot.integral-target)**2,axis=1) if method=="world_plugin"
                                 else exact_mse(offline_truth,snapshot,n))
                    rows.append({"scene":scene_id,"seed":seed,"phase":phase,"phase_frame":phase_frame,
                                 "frame":frame,"method":method,"mse":float(np.mean((result-target)**2)),
                                 "conditional_expected_mse":float(conditional.mean()),
                                 "mean_error":float(np.mean(result-target)),"negative_channel_fraction":float(np.mean(result<0)),
                                 "rays":len(ids)*n,"runtime_seconds":runtime,"memory_bytes":0 if method in ("raw_importance","neural_cv") else m.nbytes,
                                 "observed_conflicting_ray_entries":conflicts,"epoch_after":m.epoch,
                                 "known_fraction_after":float(np.isfinite(m.values[ids]).mean())})
                    if scene_id==config["scene_ids"][0] and seed==config["replicate_seeds"][0] and phase_frame==0 and phase in ("revisit","hidden_change"):
                        snapshots[f"{phase}_{method}"]=result.reshape(vh,vw,3)
                        snapshots[f"{phase}_reference"]=target.reshape(vh,vw,3)
        print(f"completed scene {scene_id}; {len(rows)} frame-method observations",flush=True)
    out=ROOT/output;out.mkdir(parents=True,exist_ok=True)
    with (out/f"{prefix}_raw.csv").open("w",newline="") as handle:
        writer=csv.DictWriter(handle,fieldnames=list(rows[0]));writer.writeheader();writer.writerows(rows)
    summary=[]
    for phase in config["phases"]:
        for method in methods:
            subset=[r for r in rows if r["phase"]==phase and r["method"]==method]
            scene_values=[np.mean([r["conditional_expected_mse"] for r in subset if r["scene"]==scene_id]) for scene_id in config["scene_ids"]]
            summary.append({"phase":phase,"method":method,"expected_mse":float(np.mean(scene_values)),
                            "expected_mse_scene_bootstrap_95":cluster_interval(scene_values),
                            "observed_mse":float(np.mean([r["mse"] for r in subset])),
                            "negative_channel_fraction":float(np.mean([r["negative_channel_fraction"] for r in subset])),
                            "cpu_median_ms":float(np.median([r["runtime_seconds"] for r in subset])*1000),
                            "cpu_p99_ms":float(np.quantile([r["runtime_seconds"] for r in subset],.99)*1000)})
    comparisons=[]
    for phase in config["phases"]:
        pairs=([("world_guarded_cv","world_active_cv"),("world_guarded_cv","world_cv"),("world_guarded_cv","raw_importance"),("world_guarded_cv","screen_cv")]
               if followup else [("world_cv","screen_cv"),("world_cv","raw_importance"),("world_active_cv","world_cv"),("world_cv","constant_world_cv"),("world_cv","world_plugin")])
        for contender,baseline in pairs:
            a=[];b=[]
            for sid in config["scene_ids"]:
                a.append(np.mean([r["conditional_expected_mse"] for r in rows if r["scene"]==sid and r["phase"]==phase and r["method"]==contender]))
                b.append(np.mean([r["conditional_expected_mse"] for r in rows if r["scene"]==sid and r["phase"]==phase and r["method"]==baseline]))
            a=np.array(a);b=np.array(b)
            rng=np.random.default_rng(299);draws=rng.integers(0,len(a),(10000,len(a)))
            ratios=1-a[draws].mean(1)/np.maximum(b[draws].mean(1),1e-30)
            comparisons.append({"phase":phase,"contender":contender,"baseline":baseline,
                                "relative_expected_mse_reduction":float(1-a.mean()/max(b.mean(),1e-30)),
                                "scene_bootstrap_95":[float(v) for v in np.percentile(ratios,[2.5,97.5])]})
    report={"protocol":config,"elapsed_seconds":time.perf_counter()-start,"environment":{"python":platform.python_version(),"numpy":np.__version__,"device":"cpu"},
            "record_count":len(rows),"total_physical_ray_calls":int(sum(r["rays"] for r in rows)),
            "per_persistent_method_memory_bytes":len(points)*len(lights)*8,
            "prior_preparation":prep,"summary":summary,"comparisons":comparisons,
            "limitations":["Only a direct-light floor/three-sphere scene family; no game engine or full path tracing.",
                           "Ray counts match. Compute, bandwidth, and VRAM do not match; report is not an equal-frame-time comparison.",
                           "Clock gap has no observations; it is not 500 fully rendered frames.",
                           "CPU timings exclude shared feature/prior preparation and privileged reference enumeration; not full-renderer frame times.",
                           "Hidden changes deliberately omit invalidation and use the stale prior; controls remain fallible.",
                           "Negative linear-radiance estimates are retained for statistical metrics. Display clipping introduces bias.",
                           "Small scene-cluster intervals characterize this generator only; no cross-game generalization claim."]}
    (out/f"{prefix}_report.json").write_text(json.dumps(report,indent=2)+"\n")
    np.savez_compressed(out/f"{prefix}_example_frames.npz",**snapshots)
    print(json.dumps({"records":len(rows),"elapsed_seconds":report["elapsed_seconds"],"comparisons":comparisons},indent=2))

if __name__=="__main__":
    parser=argparse.ArgumentParser();parser.add_argument("--followup",action="store_true")
    parser.add_argument("--output",default="reproduced_results",help="Keep new runs separate from the recorded release evidence")
    args=parser.parse_args();run(args.followup,args.output)