Uncertainty-Propagation Tree Acquisition / verify.py

Mechanism failed

Raw ⬇ ZIP
  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()