Add check_consistency.py, correct two stale figures in comments

check_consistency.py asserts every headline number against its raw CSV,
so a stale quoted value fails loudly instead of surviving a revision. It
skips the manuscript-side assertions when main.tex is absent, which is
the case in this package.

The blind-versus-permutation agreement is 0.002, not 0.0015, and the
resource-matched OMA is undefined below L=16 rather than wherever 16/L
is not an integer.
This commit is contained in:
KiHoLee
2026-08-17 00:06:25 +09:00
parent 3529ab1918
commit 47d974a5bf
2 changed files with 95 additions and 2 deletions
+93
View File
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""Final consistency check: every headline number vs its raw CSV."""
import csv
import math
import re
from pathlib import Path
base = Path(__file__).resolve().parents[1]
# The manuscript is not part of the reproducibility package, so the
# tex-side assertions are skipped when it is absent and the data-side
# assertions still run.
_tex_path = base / "main.tex"
HAVE_TEX = _tex_path.exists()
tex = _tex_path.read_text(encoding="utf-8") if HAVE_TEX else ""
def rows(name):
with open(base / "data" / name) as f:
return list(csv.DictReader(f))
def col(name, k):
return [float(r[k]) for r in rows(name) if r[k] != "nan"]
ok = True
def chk(label, cond, detail, needs_tex=False):
global ok
if needs_tex and not HAVE_TEX:
print(" SKIP " + label + " :: main.tex not in this package")
return
print((" PASS " if cond else " FAIL ") + label + " :: " + detail)
if not cond:
ok = False
print("headline numbers vs raw data")
# 1.27x key-length ratio
k = rows("sec_keylen.csv")
r64 = [x for x in k if int(x["L"]) == 64][0]
ratio = float(r64["oma"]) / float(r64["legit_ser"])
chk("key-length ratio 1.27", round(ratio, 2) == 1.27, "%.4f" % ratio)
chk("1.27 in tex", tex.count("1.27") >= 2, "%d occurrences" % tex.count("1.27"), needs_tex=True)
# blind-jammer gap
g = col("sec_jam_gap.csv", "gap_db")
chk("gap 7.4-8.1 dB", round(min(g), 1) == 7.4 and round(max(g), 1) == 8.1,
"%.3f to %.3f" % (min(g), max(g)))
chk("no stale 8.5 dB", "8.5$~dB" not in tex, "searched tex", needs_tex=True)
lin = (10 ** (min(g) / 10), 10 ** (max(g) / 10))
chk("about six times power", lin[0] < 6.5 and lin[1] > 5.5,
"%.2f to %.2f" % lin)
# blind vs permutation
j = rows("sec_jam_cmp.csv")
dmax = max(abs(float(r["blind"]) - float(r["perm_blind"])) for r in j)
chk("within 0.002", dmax <= 0.002, "%.5f" % dmax)
chk("no stale 0.0015 in jamming", "$0.0015$ of the proposed" not in tex, "ok", needs_tex=True)
# brute force
b = rows("sec_brute_cmp.csv")
sm = float(b[-1]["ser_mask"])
chk("brute 0.76 both places", tex.count("$0.76$") >= 2, "%.4f measured" % sm, needs_tex=True)
chk("no stale 0.75 in summary",
"$0.75$ after $10^{6}$" not in tex, "summary row", needs_tex=True)
# refresh
rs = {r["scheme"]: r for r in rows("refresh_summary.csv")}
chk("refresh 64.8 bits",
round(float(rs["Invariant"]["entropy_bits"]), 1) == 64.8,
"%.3f" % float(rs["Invariant"]["entropy_bits"]))
chk("fixed key 15.0 bits",
round(float(rs["None (fixed key)"]["entropy_bits"]), 1) == 15.0,
"%.4f" % float(rs["None (fixed key)"]["entropy_bits"]))
# permutation KPA
pk = rows("pkpa.csv")
p6 = float([r for r in pk if r["n_frames"] == "6"][0]["eve_ser"])
chk("perm KPA at N=6 near 0.303", abs(p6 - 0.303) < 0.005, "%.4f" % p6)
# abstract
a = (tex.split(r"\begin{abstract}")[1].split(r"\end{abstract}")[0].strip()
if HAVE_TEX else "")
w = len(re.split(r"\s+", a)) if a else 0
chk("abstract <= 250 words", w <= 250, "%d words" % w, needs_tex=True)
chk("abstract has no abbreviations",
not re.findall(r"\b[A-Z]{2,}\b", a), str(re.findall(r"\b[A-Z]{2,}\b", a)), needs_tex=True)
print()
print("ALL CONSISTENT" if ok else "INCONSISTENCIES FOUND")
+2 -2
View File
@@ -136,7 +136,7 @@ def fig_snr():
def fig_keylen():
"""The OMA reference is the resource-matched one of oma_ser_keylen,
which is undefined at key lengths where 16/L is not an integer; those
which is undefined below L=16 unless 16/L is an integer; those
rows carry nan and are skipped."""
r = load("sec_keylen.csv")
x = col(r, "L", int)
@@ -169,7 +169,7 @@ def fig_jam():
markevery=me, label=LBL["mask"] + ", matched")
ax.plot(x, col(r, "oma_targeted"), color=C_PUB, marker="^", ls=":",
markevery=me, label=LBL["oma"] + ", targeted")
# the two blind curves agree to 0.0015; deliberate layering
# the two blind curves agree to 0.002; deliberate layering
ax.plot(x, col(r, "blind"), color=C_LEGIT, marker="o", ls="-",
markevery=me, label=LBL["mask"] + ", blind", **UNDER)
ax.plot(x, col(r, "perm_blind"), color=C_EVE, marker="s", ls="-.",