LittlePlyResearch notebook

verify_openings_v1.py

python · 64 lines · Sanitized derivative

Line 1 ↗

Sanitized derivative: private paths or personal test identities use explicit placeholders. Original line count is preserved.

Version & provenance · data-cm7

Recorded SHA-256 ce3a38a5d6a2b3eec961ff12fac9260264c55300781b0f9515554bddb6001a09Rendered SHA-256 f32f3827c06b50f9b1a84c6ff7d9a30e6380ae2014c2a6846f484fbd7e9a0d7e

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"""Single-CPU fixed-node opening screening; scores are approximate, never exact."""
2import collections,hashlib,json,time
3from pathlib import Path
4import numpy as np
5from prepare_openings_v1 import OUT,c,ROOT
6from records import DTYPE,atomic_json,digest,sha
7import chess.engine
8ENGINE=Path('/work/src/stockfish/stockfish-ubuntu-x86-64-avx2')
9POLICY=dict(nodes=[250000,1000000],multipv=5,threads=1,hash_mb=64,max_gap_cp=30,max_score_change_cp=50,min_depth=[10,12],max_wall_seconds=1800,label_kind='approximate_engine_screened_opening',exact=False)
10
11def acceptable(first,second,supported):
12    if not first or not second:return []
13    # A bound, mate or missing score makes this screen inconclusive.
14    if any(r['cp'] is None or r['bound'] for r in first+second):return []
15    a={r['move']:r for r in first};b={r['move']:r for r in second};best_a=max(r['cp'] for r in first);best_b=max(r['cp'] for r in second)
16    return sorted(m for m in set(a)&set(b)&set(supported) if a[m]['depth']>=10 and b[m]['depth']>=12 and best_a-a[m]['cp']<=30 and best_b-b[m]['cp']<=30 and abs(a[m]['cp']-b[m]['cp'])<=50)
17
18def analyse(engine,board,nodes,game_id):
19    engine.configure({'Clear Hash':None})
20    infos=engine.analyse(board,chess.engine.Limit(nodes=nodes),multipv=5,game=game_id)
21    out=[]
22    for info in infos:
23        pv=info.get('pv',[])
24        if not pv:continue
25        score=info.get('score');cp=None if score is None else score.pov(board.turn).score()
26        out.append(dict(move=pv[0].uci(),cp=cp,mate=None if score is None else score.pov(board.turn).mate(),bound=bool(info.get('lowerbound') or info.get('upperbound')),depth=info.get('depth',0),nodes=info.get('nodes',0),time=info.get('time'),pv=[m.uci() for m in pv],multipv=info.get('multipv')))
27    return out
28
29def main():
30    frozen=json.loads((OUT/'frozen-selection.json').read_text());assert sha(OUT/'candidates.jsonl')==frozen['candidates_sha256']
31    if (OUT/'engine-audit.jsonl').exists():raise ValueError('refuse audit overwrite')
32    candidates=[json.loads(x) for x in (OUT/'candidates.jsonl').read_text().splitlines()]
33    engine=chess.engine.SimpleEngine.popen_uci(str(ENGINE),cwd=str(OUT),timeout=30)
34    engine.configure({'Threads':1,'Hash':64,'UCI_AnalyseMode':True,'UCI_LimitStrength':False,'Skill Level':20,'SyzygyPath':''})
35    ident=dict(engine_id=engine.id,binary=str(ENGINE),binary_sha256=sha(ENGINE),policy=POLICY,code_sha256=sha(Path(__file__)),selection_sha256=sha(OUT/'frozen-selection.json'),candidate_sha256=sha(OUT/'candidates.jsonl'),nnue=dict(default_name=engine.options['EvalFile'].default,external_in_working_dir=(OUT/engine.options['EvalFile'].default).exists(),external_beside_binary=(ENGINE.parent/engine.options['EvalFile'].default).exists()),priority='one process; nice10 inherited by engine; no GPU')
36    atomic_json(OUT/'engine-policy.json',ident);metadata=[];records=[];stats=collections.Counter();start=time.monotonic()
37    try:
38        with (OUT/'engine-audit.jsonl').open('x') as audit:
39            for idx,m in enumerate(candidates):
40                if time.monotonic()-start>POLICY['max_wall_seconds']:stats['wall_budget_unprocessed']=len(candidates)-idx;break
41                board=c.from_history(m['history_start_fen'],m['history_uci']);assert board.fen(en_passant='fen')==m['fen']
42                assert not board.is_game_over(claim_draw=True) and not board.is_repetition(2)
43                first=analyse(engine,board,250000,object());second=[]
44                supported=set(m['book_moves']);pre=first and all(r['cp'] is not None and not r['bound'] for r in first)
45                if pre:
46                    best=max(r['cp'] for r in first);pre=any(r['move'] in supported and r['depth']>=10 and best-r['cp']<=30 for r in first)
47                if pre:second=analyse(engine,board,1000000,object())
48                moves=acceptable(first,second,supported)
49                result=dict(candidate_index=idx,position_key=m['position_key'],split=m['split'],first=first,second=second,accepted_moves=moves,unassessed_supported_moves=sorted(supported-{r['move'] for r in second}),status='accepted_approximate' if moves else 'withheld_screen_inconclusive_or_disagreement')
50                audit.write(json.dumps(result)+'\n');audit.flush();stats['evaluated']+=1;stats['accepted' if moves else 'withheld']+=1
51                if moves:
52                    move=c.chess.Move.from_uci(moves[0]);e=c.example(board,move,16);row=np.zeros((),dtype=DTYPE);row['x']=e['input_ids'];row['y']=e['labels'];row['attention']=e['attention_mask'];row['source']=2;row['split']=m['split'];row['game']=len(metadata);row['ply']=m['source_ply'];row['fullmove']=board.fullmove_number;row['key']=np.frombuffer(c.position_key(board),dtype=np.uint8)
53                    records.append(row);metadata.append({**m,'engine_status':'accepted_approximate','candidate_index':idx,'accepted_moves':moves,'tied_target_triples':[c.triple(c.chess.Move.from_uci(u)) for u in moves],'selected_move':move.uci(),'complete_preserving_move_set':False,'confidence':'book-supported alternatives passed two finite-node engine screens; not exact or proven optimal','history_dropout':False})
54                if (idx+1)%25==0:print(json.dumps(dict(stats=stats,seconds=time.monotonic()-start)),flush=True)
55    finally:engine.quit()
56    (OUT/'metadata.jsonl').write_text(''.join(json.dumps(m)+'\n' for m in metadata));files=[]
57    for split in (0,1):
58        a=np.asarray([r for r in records if int(r['split'])==split],dtype=DTYPE);p=OUT/f'records-{split:06d}.bin';a.tofile(p);files.append(dict(name=p.name,rows=len(a),source=2,split=split,sha256=sha(p)))
59    shared=dict(position_ids=list(range(122)),loss_mask=[int(i in (119,120,121)) for i in range(122)],target_positions=[119,120,121]);atomic_json(OUT/'shared.json',shared)
60    identity=dict(engine_policy_sha256=sha(OUT/'engine-policy.json'),frozen_selection_sha256=sha(OUT/'frozen-selection.json'),audit_sha256=sha(OUT/'engine-audit.jsonl'),label_kind=POLICY['label_kind'])
61    manifest=dict(format='chess-state-records-v2',identity=identity,identity_sha256=digest(identity),contract=c.CONTRACT,dtype=DTYPE.descr,record_bytes=416,files=files,rows=len(records),metadata_sha256=sha(OUT/'metadata.jsonl'),shared_sha256=sha(OUT/'shared.json'),label_readiness='pending_independent_review',source_id_semantics={'2':'opening-book origin; neither main nor Elite'},label_policy=POLICY,statistics=dict(stats),training_launched=False,current_run_modified=False)
62    atomic_json(OUT/'manifest.json',manifest);print(json.dumps(manifest),flush=True)
63if __name__=='__main__':main()
64