104 lines
4.7 KiB
Python
104 lines
4.7 KiB
Python
#!/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})")
|