Uncertainty-Propagation Tree Acquisition / verify.py
Mechanism failed
1import json
2import numpy as np
3
4SEED = 1099
5np.random.seed(SEED)
6
7def K(x, y, ell=0.18):
8 x = np.asarray(x)[:, None]; y = np.asarray(y)[None, :]
9 return np.exp(-0.5*((x-y)/ell)**2)
10
11def var(train, z, noise=0.04):
12 train = np.asarray(train, float); z = np.asarray(z, float)
13 A = K(train, train) + noise*np.eye(len(train))
14 cross = K(z, train)
15 q = np.linalg.solve(A, cross.T)
16 return np.maximum(0., 1.-np.sum(cross*q.T, axis=1))
17
18def red(train, action, z, w):
19 return float(np.dot(w, var(train,z)-var(np.r_[train,action],z)))
20
21def controlled_overlap():
22 train=np.array([-1.,1.]); z=np.linspace(-1,1,501); w=np.ones(len(z))/len(z)
23 observed=np.linspace(-.12,.12,8)
24 remote=np.linspace(.68,.88,8)
25 rows=[]
26 # Number of repeated/nearby points increases; all action sizes remain fixed.
27 for m in range(9):
28 b=np.r_[observed[:m], remote[:8-m]]
29 rows.append({'near_fraction':m/8., 'reduction_after_first':red(np.r_[train,observed],b,z,w)})
30 return rows
31
32def affine_tree():
33 train=np.array([-1.,1.]); z=np.linspace(-1,1,301); w=np.ones(len(z))/len(z)
34 centers=np.array([-.72,-.42,-.10,.22,.55,.82])
35 acts=[np.linspace(c-.1,c+.1,5) for c in centers]
36 gamma=.9; n=len(acts); lines={}
37 for i in range(n):
38 first=red(train,acts[i],z,w)
39 for j in range(n):
40 second=red(np.r_[train,acts[i]],acts[j],z,w)
41 lines[i,j]=(first+gamma*second, gamma*abs(i-j)/(n-1))
42 def policy(lam):
43 best=[]
44 for i in range(n):
45 j=max(range(n),key=lambda q: lines[i,q][0]-lam*lines[i,q][1])
46 best.append((lines[i,j][0]-lam*lines[i,j][1],(i,j)))
47 return max(best)
48 grid=np.linspace(0,2,2001)
49 policies=[policy(x)[1] for x in grid]
50 # Locate the first change whose adjacent paths have distinct costs.
51 chosen=None
52 for k in range(len(grid)-1):
53 if policies[k]!=policies[k+1]:
54 p,q=policies[k],policies[k+1]
55 if abs(lines[p][1]-lines[q][1])>1e-10:
56 A,B=lines[p]; C,D=lines[q]
57 exact=(A-C)/(B-D)
58 chosen={'path_before':p,'path_after':q,'predicted_lambda':exact,
59 'observed_grid_midpoint':(grid[k]+grid[k+1])/2,
60 'grid_error':abs(exact-(grid[k]+grid[k+1])/2)}
61 break
62 return chosen
63
64def comparison():
65 train0=np.array([-1.,1.]); z=np.linspace(-1,1,401); w=np.ones(len(z))/len(z)
66 centers=np.array([-.72,-.42,-.10,.22,.55,.82])
67 acts=[np.linspace(c-.1,c+.1,5) for c in centers]; gamma=.9
68 def tree(tr,lam=.8):
69 vals=[]
70 for i,a in enumerate(acts):
71 r=red(tr,a,z,w); future=max(red(np.r_[tr,a],b,z,w)-lam*abs(i-j)/(len(acts)-1) for j,b in enumerate(acts))
72 vals.append(r+gamma*future)
73 return int(np.argmax(vals))
74 out={}
75 for method in ('random','greedy','tree'):
76 tr=train0.copy(); total=0.; chosen=[]
77 for t in range(3):
78 if method=='random': i=np.random.default_rng(SEED+t).integers(len(acts))
79 elif method=='greedy': i=int(np.argmax([red(tr,a,z,w) for a in acts]))
80 else: i=tree(tr)
81 total+=red(tr,acts[i],z,w); tr=np.r_[tr,acts[i]]; chosen.append(int(i))
82 out[method]={'cumulative_reduction':total,'actions':chosen,'final_mean_variance':float(np.mean(var(tr,z)))}
83 return out
84
85def main():
86 z=np.linspace(-1,1,401); train=np.array([-.85,-.25,.35,.9])
87 before=var(train,z); after=var(np.r_[train,0.],z)
88 max_inc=float(np.max(after-before))
89 overlap=controlled_overlap()
90 vals=[r['reduction_after_first'] for r in overlap]
91 # Prediction: variance reduction decreases as the fraction of redundant points rises.
92 mono=all(vals[i+1] <= vals[i]+1e-9 for i in range(len(vals)-1))
93 tree=affine_tree()
94 result={'seed':SEED,
95 'prediction_1_variance_nonincrease':{'predicted_max_increase':0.,'observed_max_increase':max_inc,'confirmed':max_inc<=1e-9},
96 'prediction_2_redundancy_diminishes_reward':{'predicted':'monotone decrease with near/overlap fraction','sweep':overlap,'confirmed':mono,'endpoint_ratio':vals[-1]/vals[0]},
97 'prediction_3_cost_crossover':{'predicted':'lambda=(A-C)/(B-D) for affine path values','result':tree,'confirmed':tree is not None and tree['grid_error']<.002},
98 'comparison':comparison()}
99 with open('results.json','w') as f: json.dump(result,f,indent=2,default=lambda x: x.item() if hasattr(x, 'item') else x)
100 print(json.dumps(result,indent=2,default=lambda x: x.item() if hasattr(x, 'item') else x))
101if __name__=='__main__': main()