## Task 5 — VALIDATE THE AUTOMATA-LEVEL METRICS against known ground truth. ## ## Case A: the planted-rule set from diag_synthetic.nim (learnable). ## Case B: the SAME inputs with the labels shuffled (pure noise). ## The metrics must SEPARATE learning from fidgeting: ## A: settledness high and rising, churn trend falling, disagreement low. ## B: settledness low, churn high / not falling, disagreement high. ## Case C: a CONSTANT input, to confirm the kit surfaces an information-free bit. ## ## Every number printed here is MEASURED. ## Run: nim c -r -d:release --path:common_libs common_libs/tests/diag_automata_validation.nim import std/[random, strformat, strutils, algorithm] import tm_diag/diagnostics const NBits = 49 BitA = 0 BitB = 45 NoiseBit = 17 ConstBit = 20 NClasses = 3 Epochs = 15 var failures = 0 proc check(name: string, ok: bool) = if ok: echo "PASS: ", name else: echo "FAIL: ", name; inc failures proc genDataset(n, seed: int, constant = false): seq[DiagSample] = var rng = initRand(seed) for i in 0.. late(full)={lateS.overallMean:.4f} ({settlednessTrend(earlyS, lateS)})" echo "\n## CHECKS" check "A settledness is high at convergence (>= 0.50)", dA.settledness.overallMean >= 0.50 check "A churn TRENDS DOWN (falling)", dA.churn.flipTrend == "falling" and dA.churn.flipLast < dA.churn.flipFirst check "A disagreement is low (< 0.15)", dA.disagreement.overall < 0.15 check "A settledness RISES from early to late", lateS.overallMean > earlyS.overallMean check "B churn does NOT fall (flat/rising/frozen)", dB.churn.flipTrend in ["flat", "rising", "frozen"] check "A is clearly more settled than B (A - B >= 0.10)", dA.settledness.overallMean - dB.settledness.overallMean >= 0.10 check "B disagrees clearly more than A (B - A >= 0.10)", dB.disagreement.overall - dA.disagreement.overall >= 0.10 check "the pair is separated (A verdict settling, B not settling)", automataVerdict(dA) == "settling" and automataVerdict(dB) != "settling" # ── Case C: constant input ── let trainC = genDataset(2000, 3, constant = true) let dC = automataDiagnostics(tmpl, trainC, spec, epochs = Epochs, seed = 777) echo "\n## CASE C — constant input (bit 20 forced to 1)" var cbit: InputConfidence for ic in dC.inputConfidence: if ic.bit == ConstBit: cbit = ic echo &"# bit{ConstBit} constant={cbit.constant} meanCommit={cbit.meanCommitment:.4f} " & &"settled={cbit.settledFraction:.4f}" let consts = constantInputs(trainC, NBits) echo &"# constantInputs(trainC) = {consts}" check "the constant bit is flagged in the confidence table", cbit.constant check "constantInputs() surfaces the constant bit", ConstBit in consts check "a real planted bit is NOT flagged constant", not dC.inputConfidence[BitA].constant # ── Inertia sweep: how the automata metrics move with N ── echo "\n## INERTIA SWEEP — settledness / churn / disagreement vs N (10 epochs)" echo "# case,N,settledness,churnTrend,flipPer100,disagreement,verdict" for n in [16, 32, 64, 128]: let tmplN = newMachine(NBits, NClasses, 40, n, 3.0, 1) let aN = automataDiagnostics(tmplN, trainA, spec, epochs = 10, seed = 777) let bN = automataDiagnostics(tmplN, trainB, spec, epochs = 10, seed = 777) echo &"# A,{n},{aN.settledness.overallMean:.3f},{aN.churn.flipTrend}," & &"{aN.churn.flipRatePer100:.3f},{aN.disagreement.overall:.3f},{automataVerdict(aN)}" echo &"# B,{n},{bN.settledness.overallMean:.3f},{bN.churn.flipTrend}," & &"{bN.churn.flipRatePer100:.3f},{bN.disagreement.overall:.3f},{automataVerdict(bN)}" echo "" if failures > 0: echo &"{failures} check(s) FAILED" quit(1) echo "All automata-validation checks passed."