LittlePlyResearch notebook

holdout_amendment.py

python · 78 lines · Exact bytes

Line 1 ↗
Version & provenance · data-cm7

Recorded SHA-256 ed2d9db13c0251e2c498d4525e664ca87097824c388087e24bb9fa86486d8d36Rendered SHA-256 ed2d9db13c0251e2c498d4525e664ca87097824c388087e24bb9fa86486d8d36

Apache-2.0 original project code; dependencies retain their own licenses. License notes. Line links are stable within this snapshot. CM-7 completed implementation source; original and public rendered hashes recorded. Host-specific paths use /work placeholders; inspect reproduction instructions before running. Separate Rust helper retains its GPL license.

1"""Freeze stratified exact validation; exclude full source-game transpositions."""
2import collections,hashlib,json,time
3from pathlib import Path
4import numpy as np
5from inventory_inputs import ROOT,STATE,PROJECT,c,protection,aliases,_read_shard,sha
6from records import DTYPE,atomic_json,digest
7from build_curriculum import guard
8from prepare import replay
9import chess.syzygy
10OUT=ROOT/'exact-holdout-v1';OLD=ROOT/'theory-v3'
11SEED='exact-validation-family-outcome-20261029-v1'
12
13def stratified_indices(metadata,n=2000):
14    groups=collections.defaultdict(list)
15    for i,m in enumerate(metadata):groups[(chess.syzygy.normalize_tablename(m['material_family']),m['outcome'])].append(i)
16    if not 0<n<len(metadata):raise ValueError('invalid holdout size')
17    # Largest-remainder proportional allocation; ties and rows are deterministic.
18    quota={k:len(v)*n//len(metadata) for k,v in groups.items()}
19    order=sorted(groups,key=lambda k:(-(len(groups[k])*n%len(metadata)),k))
20    for k in order[:n-sum(quota.values())]:quota[k]+=1
21    chosen=[]
22    for k in sorted(groups):
23        chosen.extend(sorted(groups[k],key=lambda i:hashlib.sha256((SEED+metadata[i]['position_key']).encode()).digest())[:quota[k]])
24    return sorted(chosen),{str(k):dict(available=len(groups[k]),selected=quota[k]) for k in sorted(groups)}
25
26def export(root,indices,metadata,rows,split,protection_sha):
27    root.mkdir();items=[];selected=[]
28    for i in indices:
29        r=rows[i].copy();r['game']=len(items);r['split']=split;selected.append(r);items.append({**metadata[i],'parent_theory_metadata_index':i})
30    (root/'metadata.jsonl').write_text(''.join(json.dumps(m)+'\n' for m in items));files=[]
31    for src in (0,1):
32        a=np.asarray([r for r in selected if int(r['source'])==src],dtype=DTYPE);p=root/f'records-source{src}.bin';a.tofile(p);files.append(dict(name=p.name,rows=len(a),source=src,split=split,sha256=sha(p)))
33    atomic_json(root/'shared.json',json.loads((OLD/'shared.json').read_text()))
34    ident=dict(parent_manifest_sha256=sha(OLD/'manifest.json'),amendment_code_sha256=sha(Path(__file__)),selection_sha256=sha(OUT/'selection.json'),protection_sha256=protection_sha,split=split)
35    atomic_json(root/'manifest.json',dict(format='chess-state-records-v2',identity=ident,identity_sha256=digest(ident),record_bytes=416,dtype=DTYPE.descr,contract=c.CONTRACT,files=files,rows=len(items),metadata_sha256=sha(root/'metadata.jsonl'),shared_sha256=sha(root/'shared.json'),label_readiness='pending_independent_review',label_semantics='unchanged exact zero-counter FEN-only labels; full ties retained'))
36
37def main():
38    if OUT.exists():raise ValueError('refuse overwrite')
39    guard(300_000_000);OUT.mkdir();db,config=protection()
40    metadata=[json.loads(x) for x in (OLD/'metadata.jsonl').read_text().splitlines()];old=json.loads((OLD/'manifest.json').read_text());assert old['label_readiness']=='independently_reviewed_ready'
41    rows={}
42    for f in old['files']:
43        assert sha(OLD/f['name'])==f['sha256']
44        for r in np.fromfile(OLD/f['name'],dtype=DTYPE):rows[int(r['game'])]=r
45    selected,strata=stratified_indices(metadata);selected_set=set(selected)
46    frozen=dict(seed=SEED,selection='proportional largest remainder by normalized family/outcome; SHA256 within stratum',parent_manifest_sha256=sha(OLD/'manifest.json'),selected_metadata_indices=selected,selected_keys=[metadata[i]['position_key'] for i in selected],strata=strata,model_results_used=False,limitation='heldout from next continuation only; inherited CM6 may have seen these states')
47    atomic_json(OUT/'selection.json',frozen)
48    wanted={metadata[i]['source_sequence_sha256'] for i in selected};heldout_aliases=set(a for i in selected for a in metadata[i]['game_aliases'])
49    gameids=[]
50    for gid,raw in db.execute('SELECT id,metadata FROM games'):
51        gm=json.loads(raw)
52        if heldout_aliases.intersection(aliases(gm)):gameids.append(gid)
53    keys=set();found=set();receipt=[];start=time.monotonic()
54    for src,ref in enumerate(config['sources']):
55        root=Path(ref['root']);m=json.loads((root/'manifest.json').read_text());assert sha(root/'manifest.json')==ref['manifest_sha256']
56        shards=sorted((s for s in m['shards'] if s['split']=='train'),key=lambda s:digest([config['seed'],sorted(s['files'])]))
57        sourcewanted={metadata[i]['source_sequence_sha256'] for i in selected if int(rows[i]['source'])==src};scanned=0
58        for shard in shards:
59            tokens,offsets,metas=_read_shard(root,shard)
60            for a,b,meta in zip(offsets,offsets[1:],metas):
61                scanned+=1;seq=meta['sequence_sha256']
62                if seq not in sourcewanted or seq in found:continue
63                _,gamekeys,_=replay((tokens[a:b],meta,'protect',config['seed'],src));keys.update(gamekeys);found.add(seq)
64                receipt.append(dict(source=src,sequence_sha256=seq,game_aliases=aliases(meta),positions_including_terminal=len(gamekeys),position_keys_sha256=hashlib.sha256(b''.join(gamekeys)).hexdigest(),source_shard=shard))
65            if sourcewanted<=found:break
66        print(json.dumps(dict(source=src,games_scanned=scanned,found=len(found),wanted=len(wanted),seconds=time.monotonic()-start)),flush=True)
67    if found!=wanted:raise ValueError('missing full heldout games')
68    if not {bytes.fromhex(metadata[i]['position_key']) for i in selected}<=keys:raise ValueError('selected keys missing from games')
69    np.asarray(sorted(keys),dtype='V32').tofile(OUT/'protected-keys.bin');np.asarray(sorted(gameids),dtype='<u4').tofile(OUT/'protected-game-ids.bin')
70    atomic_json(OUT/'game-replay-receipt.json',receipt)
71    protected=dict(selection_sha256=sha(OUT/'selection.json'),keys_sha256=sha(OUT/'protected-keys.bin'),key_count=len(keys),game_ids_sha256=sha(OUT/'protected-game-ids.bin'),game_id_count=len(gameids),aliases=sorted(heldout_aliases),source_sequences=sorted(wanted),full_game_replay_sha256=sha(OUT/'game-replay-receipt.json'),source_manifests=config['sources'],readiness='pending_independent_review')
72    atomic_json(OUT/'protection.json',protected)
73    kept=[i for i,m in enumerate(metadata) if i not in selected_set and bytes.fromhex(m['position_key']) not in keys and not heldout_aliases.intersection(m['game_aliases'])]
74    export(ROOT/'theory-v4',kept,metadata,rows,0,sha(OUT/'protection.json'));export(ROOT/'exact-validation-v1',selected,metadata,rows,1,sha(OUT/'protection.json'))
75    atomic_json(OUT/'summary.json',dict(validation_rows=len(selected),training_theory_rows=len(kept),other_theory_rows_removed=len(metadata)-len(selected)-len(kept),selected_source_games=len(wanted),protected_keys=len(keys),protected_game_ids=len(gameids)))
76    print((OUT/'summary.json').read_text(),flush=True)
77if __name__=='__main__':main()
78