textmachine/eval/bank_autonomy/m22_consolidation.py

104 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""ЗАМОR 22: §C2-3 consolidation weights at n>=2. $0.
Engine's bank-stop `drafts:` are already ScoreVariants-ordered => drafts[0] = engine §C2-3-top.
We reproduce the freq+lemma part exactly (neighbour=1.0 cold; conform neutral in python) and detect
conformance-decisive cases empirically as (name/place where engine-top != my freq/lemma-top)."""
from parse_common import parse_bankstop, parse_minedsig
import re
FREQ_FLOOR=0.5; LEMMA_PEN=0.4
def well_formed(dst):
t=dst.strip()
if len(t)<2: return False
if t.startswith("-") or t.endswith("-"): return False
if any(ch in t for ch in "[]{}<>|\t\n"): return False
return True
def score_variants(variants):
"""variants: list of (dst, chunks). Return ranked list of (dst,chunks,score) by §C2-3
share*lemma (conform=1, neighbour=1). Deterministic tiebreak: score desc, chunks desc, dst asc."""
if not variants: return []
maxc=max(c for _,c in variants) or 1
scored=[]
for dst,c in variants:
share=FREQ_FLOOR+(1-FREQ_FLOOR)*c/maxc
s=share*(1.0) # conform neutral in python
if not well_formed(dst): s*=LEMMA_PEN
scored.append((dst,c,s))
scored.sort(key=lambda x:(-x[2],-x[1],x[0]))
return scored
def freq_top(variants):
return sorted(variants,key=lambda x:(-x[1],x[0]))[0][0]
bs=parse_bankstop()
ms={r["src"]:r for r in parse_minedsig()}
# n>=2 population: >=2 distinct draft variants
n2={s:r for s,r in bs.items() if len({d for d,_ in r["drafts"]})>=2}
print(f"=== POPULATION: total bank-stop terms={len(bs)} ; n>=2 (>=2 distinct drafts)={len(n2)} ===")
by_type={}
for s,r in n2.items(): by_type[r["type"]]=by_type.get(r["type"],0)+1
print(" n>=2 by type:", by_type)
# --- (i) is formula a pure ranking (no score 0)? ---
zero=0
for s,r in n2.items():
for d,c,sc in score_variants(r["drafts"]):
if sc<=0: zero+=1
print(f"\n=== (i) pure ranking: variants scoring 0 = {zero} (expect 0) ===")
# --- SECOND PATH cross-check: bank-stop drafts vs mined-sig other_proposals ---
mismatch=[]
for s,r in n2.items():
bs_set={d:c for d,c in r["drafts"]}
if s in ms:
# mined-sig lists the NON-winning as "other proposals"; winner is dst. Reconstruct full set.
prop={d:c for d,c in ms[s].get("other_proposals",[])}
# the winner variant equals ms dst with its own chunk count (banknote_chunks) — approx
# We compare the set of NON-top variants counts.
bs_others={d:c for d,c in r["drafts"][1:]}
if prop and bs_others and set(prop)!=set(bs_others):
mismatch.append((s,bs_others,prop))
print(f"\n=== SECOND PATH: bank-stop 'other drafts' vs mined-sig 'other proposals' mismatch = {len(mismatch)} of {sum(1 for s in n2 if s in ms and ms[s].get('other_proposals'))} comparable ===")
for s,a,b in mismatch[:8]:
print(f" {s}: bankstop={a} minedsig={b}")
# --- (a) TERM contested: engine §C2-3-top == freq-majority-top? (conform inert on terms) ---
term_n2={s:r for s,r in n2.items() if r["type"]=="term"}
a_ok=a_bad=0; a_examples=[]
for s,r in term_n2.items():
eng_top=r["drafts"][0][0]
ft=freq_top(r["drafts"])
if eng_top==ft: a_ok+=1
else:
a_bad+=1; a_examples.append((s,eng_top,ft,r["drafts"]))
print(f"\n=== (a) TERM-contested (N={len(term_n2)}): engine-top==freq-majority-top: {a_ok} ; differ: {a_bad} ===")
for s,e,f,dr in a_examples[:10]:
print(f" {s}: engine-top={e} freq-top={f} drafts={dr}")
# --- (b) NAME/PLACE contested: engine-top != my freq/lemma-top => conformance decisive ---
np_n2={s:r for s,r in n2.items() if r["type"] in ("name","place")}
conf_flips=[]; conf_same=0
for s,r in np_n2.items():
eng_top=r["drafts"][0][0]
my_top=score_variants(r["drafts"])[0][0]
if eng_top!=my_top:
conf_flips.append((s,r["type"],eng_top,my_top,r["drafts"]))
else: conf_same+=1
print(f"\n=== (b) NAME/PLACE-contested (N={len(np_n2)}): conform-decisive (engine-top != freq/lemma-top): {len(conf_flips)} ; same: {conf_same} ===")
for s,t,e,m,dr in conf_flips[:12]:
print(f" {s} [{t}]: engine-top={e} freqtop={m} drafts={dr}")
# --- (c) engine §C2-3-top-variant vs FINAL dst (terminologist) ---
follow=diverge=0; div_examples=[]
for s,r in n2.items():
eng_top=r["drafts"][0][0]
final=r["dst"]
# normalize light: strip quotes/case for a lenient match too
if final==eng_top: follow+=1
else:
diverge+=1; div_examples.append((s,r["type"],eng_top,final,[d for d,_ in r["drafts"]]))
print(f"\n=== (c) engine §C2-3-top vs FINAL terminologist dst (N={len(n2)}): follow={follow} diverge={diverge} ({diverge/len(n2)*100:.1f}%) ===")
for s,t,e,f,dr in div_examples[:15]:
print(f" {s} [{t}]: §C2-3-top='{e}' -> FINAL='{f}' (drafts={dr})")