|
1 | 1 | #!/usr/bin/env python3 |
2 | | -"""V111 FAST SCREEN — decision-changing residual tests in one shared pass. |
3 | | -Screen only; winners require untouched full verification before promotion. |
4 | | -Frozen before results: deterministic hash sample, V97 baseline, grouped OOF, no cross-test aggregates. |
5 | | -Primary question: which missing representation family can separate V97 residual collisions? |
6 | | -""" |
7 | | -from __future__ import annotations |
8 | | -import argparse, hashlib, json |
| 2 | +"""Temporary isolated-runner shim: execute frozen V112 fast raw-observable screen.""" |
| 3 | +from v112_fast_raw_observable_screen import main |
| 4 | +import argparse |
9 | 5 | from pathlib import Path |
10 | | -import numpy as np |
11 | | -from sklearn.linear_model import LogisticRegression |
12 | | -from sklearn.metrics import log_loss |
13 | | -from sklearn.model_selection import GroupKFold |
14 | | -from sklearn.preprocessing import StandardScaler |
15 | | -from v110_residual_collider_state_discovery import hb, ll, logit, p97_predict, state_vec |
16 | | -from v71_mastery_events import load_transcript |
17 | | -from v75_canonical_trajectory import load_training, SEED |
18 | | -from v81_target_segment_phase import choose_target_segment |
19 | | -from v85_evidence_state import build_v75, evidence_events |
20 | | -from v94_related_control import segmented_control, build_control |
21 | | - |
22 | | -EPS=1e-5 |
23 | | - |
24 | | -def h(x): return int(hashlib.sha256(str(x).encode()).hexdigest()[:16],16) |
25 | | -def fit_oof(P,S,y,groups): |
26 | | - q=np.zeros(len(y)); k=min(4,len(np.unique(groups))) |
27 | | - for tr,va in GroupKFold(k).split(S,y,groups): |
28 | | - sc=StandardScaler().fit(S[tr]); A=sc.transform(S[tr]); B=sc.transform(S[va]) |
29 | | - m=LogisticRegression(C=.15,max_iter=250,solver='liblinear',random_state=SEED).fit(np.c_[logit(P[tr]),A],y[tr]) |
30 | | - q[va]=m.predict_proba(np.c_[logit(P[va]),B])[:,1] |
31 | | - return np.clip(q,EPS,1-EPS) |
32 | | -def evvec(E, mode): |
33 | | - if not E: return np.zeros(12) |
34 | | - pos=np.array([float(e['pos']) for e in E]); neg=np.array([float(e['neg']) for e in E]); ind=np.array([float(e['independent']) for e in E]); ass=np.array([float(e['assistance']) for e in E]); rel=np.array([float(e['rel']) for e in E]); n=len(E) |
35 | | - if mode=='CONTENT': |
36 | | - return np.array([n,pos.mean(),neg.mean(),ind.mean(),ass.mean(),rel.mean(),(pos*ind).mean(),(neg*rel).mean(),rel.max(),rel[-1],pos.sum()/max(1,n),neg.sum()/max(1,n)]) |
37 | | - if mode=='TERMINAL': |
38 | | - z=np.arange(n); lastp=np.max(np.where(pos>0,z,-1)); lastn=np.max(np.where(neg>0,z,-1)); lasti=np.max(np.where((pos*ind)>0,z,-1)); |
39 | | - return np.array([n,pos[-1],neg[-1],ind[-1],ass[-1],rel[-1],lastp/n,lastn/n,lasti/n,(lasti-lastn)/n,(lastp-lastn)/n,(pos[-min(3,n):]*ind[-min(3,n):]).mean()]) |
40 | | - if mode=='ORDER': |
41 | | - return state_vec(E,(.7,.5,.7,.75),False)[:12] |
42 | | - if mode=='ORDER_ABLATE': |
43 | | - return state_vec(E,(.7,.5,.7,.75),True)[:12] |
44 | | - raise ValueError(mode) |
45 | | - |
46 | | -def main(a): |
47 | | - f=load_training(a.features,a.labels).reset_index(drop=True) |
48 | | - print('features columns',list(f.columns),flush=True) |
49 | | - # deterministic balanced screen: discovery objectives only, <= N rows, preserve many objectives |
50 | | - obj=(f.learning_objective_id if 'learning_objective_id' in f else f.learning_objective).astype(str).to_numpy() |
51 | | - cand=np.where(np.array([hb(x,5)!=0 for x in obj]))[0] |
52 | | - ix=np.array(sorted(cand,key=lambda i:h(f.response_id.iloc[i]))[:a.rows]); f=f.iloc[ix].reset_index(drop=True) |
53 | | - y=f.target.to_numpy(int); obj=(f.learning_objective_id if 'learning_objective_id' in f else f.learning_objective).astype(str).to_numpy(); support=f.learning_objective.astype(str).to_numpy(); sess=f.session_id.astype(str).to_numpy() |
54 | | - cache={sid:load_transcript(a.transcripts/f'{sid}.csv') for sid in np.unique(sess)} |
55 | | - rt=[]; rz=[]; EV=[] |
56 | | - for i,r in f.iterrows(): |
57 | | - t,z=segmented_control(cache[str(r.session_id)],str(r.learning_objective),'related'); rt.append(t); rz.append(z) |
58 | | - seg,_=choose_target_segment(cache[str(r.session_id)],str(r.learning_objective)); EV.append(evidence_events(seg,str(r.learning_objective))) |
59 | | - X75=build_v75(f,cache); Xr=build_control(rt,rz) |
60 | | - P=np.zeros(len(f)); splits=list(GroupKFold(min(4,len(np.unique(obj)))).split(np.zeros(len(f)),y,obj)) |
61 | | - for tr,va in splits: P[va],_=p97_predict(X75,Xr,y,tr,va,support) |
62 | | - base=ll(y,P); out={'rows':len(f),'objectives':len(np.unique(obj)),'v97':base,'tests':{}} |
63 | | - mats={m:np.vstack([evvec(E,m) for E in EV]) for m in ['CONTENT','TERMINAL','ORDER','ORDER_ABLATE']} |
64 | | - # Highest-impact screen A: does event content carry missing information at all? |
65 | | - for m,S in mats.items(): |
66 | | - q=fit_oof(P,S,y,obj); out['tests'][m]={'ll':ll(y,q),'gain':base-ll(y,q)} |
67 | | - out['tests']['CHRONOLOGY_CAUSAL']={'gain':out['tests']['ORDER']['gain']-out['tests']['ORDER_ABLATE']['gain']} |
68 | | - # Screen B: objective relevance is the suspected bottleneck. Remove rel dimensions and compare. |
69 | | - S=mats['CONTENT'].copy(); Sr=S.copy(); Sr[:,5]=0; Sr[:,7]=0; Sr[:,8]=0; Sr[:,9]=0 |
70 | | - qr=fit_oof(P,Sr,y,obj); out['tests']['RELEVANCE_ABLATION']={'ll':ll(y,qr),'gain':base-ll(y,qr),'relevance_value':out['tests']['CONTENT']['gain']-(base-ll(y,qr))} |
71 | | - # Screen C: tight residual geometry. Opposite-label nearest neighbor distance in P within objective. |
72 | | - ds=[] |
73 | | - for o in np.unique(obj): |
74 | | - z=np.where(obj==o)[0]; a0=z[y[z]==0]; a1=z[y[z]==1] |
75 | | - if len(a0) and len(a1): |
76 | | - p1=np.sort(P[a1]); ds.extend([float(np.min(np.abs(p1-P[i]))) for i in a0]) |
77 | | - out['residual_geometry']={'opposite_nn_p_median':float(np.median(ds)) if ds else None,'opposite_nn_p_p10':float(np.quantile(ds,.1)) if ds else None,'pairs_basis':len(ds)} |
78 | | - gains={k:v.get('gain',-9) for k,v in out['tests'].items() if isinstance(v,dict)}; winner=max(gains,key=gains.get) |
79 | | - out['decision']={'winner':winner,'winner_gain':gains[winner],'rule':'Escalate only a family with >=.003 grouped-OOF screen gain; chronology requires >=.001 ORDER-over-ABLATE. Otherwise change observable/extraction, not grammar.'} |
80 | | - Path(a.out).write_text(json.dumps(out,indent=2)); print(json.dumps(out,indent=2),flush=True) |
81 | 6 | if __name__=='__main__': |
82 | | - p=argparse.ArgumentParser(); p.add_argument('--features',type=Path,required=True); p.add_argument('--labels',type=Path,required=True); p.add_argument('--transcripts',type=Path,required=True); p.add_argument('--rows',type=int,default=2500); p.add_argument('--out',default='v111_fast_residual_screen.json'); main(p.parse_args()) |
| 7 | + p=argparse.ArgumentParser();p.add_argument('--features',type=Path,required=True);p.add_argument('--labels',type=Path,required=True);p.add_argument('--transcripts',type=Path,required=True);p.add_argument('--rows',type=int,default=2500);p.add_argument('--out',default='v111_fast_residual_screen.json');main(p.parse_args()) |
0 commit comments