#!/usr/bin/env python3 """55_verificador_ncm.py — v0.6.0: o validador do Pensamento passa a ser a PRÓPRIA CONFIANÇA DO NCM, calibrada (r-21 §3.1 fechado; provas r-23). Demos: 1. calibração de temperatura em dados retidos (V-1): T*, ECE antes/depois; 2. soundness sem oráculo (V-2): P(erro|aceito) ≤ 1−τ_c+ECE+folga; 3. τ_c por quantil DKW (V-3); 4. ciclo d do Pensamento com o verificador NCM (produção, sem oráculo) — ganho de confiança vs 1 rede isolada; 5. escalonamento com N sob o verificador NCM. Saída: resultados/verificador_ncm_v060.json """ import json, os, time def main(): import khtst_rust.nucleo_rust as nr pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) res = {"versao": "0.6.0", "modulo": nr.versao(), "demos": {}} # -------------------------------------------- 1-3: calibração + soundness print("=== Verificador NCM: calibração (V-1) + soundness (V-2) + DKW (V-3) ===", flush=True) t0 = time.time() v = nr.demo_verificador_ncm(n=3000, k=24, semente=42) dt = time.time() - t0 print(f" temperatura calibrada T*: {v['temperatura_calibrada']:.4f}") print(f" ECE: {v['ece_antes']:.4f} -> {v['ece_depois']:.4f} (NLL {v['nll_antes']:.4f} -> {v['nll_depois']:.4f})") print(f" tau_c (DKW, eps=0.25): {v['tau_c_dkw']:.4f}") print(f" P(erro|aceito) = {v['p_erro_aceito']:.4f} <= cota {v['cota_soundness']:.4f} -> {v['soundness_ok']}") print(f" (referência: acerto do ORÁCULO no mesmo problema = {v['acerto_oraculo_referencia']:.4f} — inacessível em produção)") res["demos"]["calibracao_soundness"] = {**v, "tempo_s": dt} # -------------------------------------------- 4: ciclo d SEM oráculo print("\n=== Ciclo d com verificador NCM (sem oráculo) ===", flush=True) t0 = time.time() d = nr.demo_pensamento_ncm( d_cond=12, d_saida=6, n_tentativas=5, passos_treino=220, limiar_conf=0.92, orcamento=6, semente=42, ) dt = time.time() - t0 print(f" treino cooperativo: {d['perda_treino_inicial']:.4f} -> {d['perda_treino_final']:.4f} (aprendeu: {d['treino_aprendeu']})") print(f" ECE do verificador: {d['ece_verificador_antes']:.4f} -> {d['ece_verificador_depois']:.4f} (T*={d['temperatura_calibrada']:.3f})") print(f" ciclo d: {d['iteracoes_ciclo_d_media']:.1f} iterações médias | conf base 1 rede: {d['confianca_base_1_rede']:.4f}") print(f" conf Pensamento (N=5, verificador NCM): {d['confianca_pensamento']:.4f} (ganho {d['ganho_confianca']:+.4f})") print(f" OOD honesto: base {d['confianca_ood_base']:.4f} -> pensamento {d['confianca_ood_pensamento']:.4f} (iterações {d['iteracoes_ood']})") res["demos"]["ciclo_d_sem_oraculo"] = { **d, "tempo_s": dt, "gate_aprendeu": d["treino_aprendeu"], "gate_terminou": d["iteracoes_ciclo_d_media"] <= 6, "gate_sem_oraculo": True, } # -------------------------------------------- 5: escalonamento com N print("\n=== Escalonamento com N (verificador NCM, consultas retidas) ===", flush=True) escal = [] for n in (1, 2, 4, 8): r = nr.demo_pensamento_ncm( d_cond=12, d_saida=6, n_tentativas=n, passos_treino=180, limiar_conf=0.95, orcamento=8, semente=100 + n, ) escal.append({ "n": n, "conf_base": r["confianca_base_1_rede"], "conf_pensamento": r["confianca_pensamento"], "ganho": r["ganho_confianca"], "iteracoes": r["iteracoes_ciclo_d_media"], }) print(f" N={n}: base {r['confianca_base_1_rede']:.4f} -> pensamento {r['confianca_pensamento']:.4f} (ganho {r['ganho_confianca']:+.4f})") n1, nn = escal[0]["conf_pensamento"], escal[-1]["conf_pensamento"] res["demos"]["escalonamento_n"] = { "serie": escal, "confianca_n1": n1, "confianca_n_max": nn, "gate_tp2_ncm": nn >= n1 - 0.05, } # ------------------------------------------------------------------ resumo gates = [] for nome, s in res["demos"].items(): gates += [(f"{nome}.{g[5:]}", val) for g, val in s.items() if g.startswith("gate_")] # gates aninhados do Rust (honestidade: conta TODOS) if isinstance(s.get("gates"), dict): gates += [(f"{nome}.{g[5:]}", val) for g, val in s["gates"].items() if g.startswith("gate_")] ok = sum(1 for _, val in gates if val) res["resumo"] = {"gates_totais": len(gates), "gates_ok": ok, "todos_verdes": ok == len(gates)} print(f"\n=== RESUMO: {ok}/{len(gates)} gates verdes ===") os.makedirs(os.path.join(pasta, "resultados"), exist_ok=True) with open(os.path.join(pasta, "resultados", "verificador_ncm_v060.json"), "w") as f: json.dump(res, f, indent=1, ensure_ascii=False) print("salvo: resultados/verificador_ncm_v060.json") if not res["resumo"]["todos_verdes"]: raise SystemExit(1) if __name__ == "__main__": main()