File size: 3,429 Bytes
4dbc907
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python3
"""62_suite_fnh.py — v0.7.0: gates da FNH + ablação rotação/ortogonalidade
EM TREINO (r-29 §3; requisitos: "construir em rust fnh_layer quando a
punição estiver alta" + "testar e verificar uso de rotação e
ortogonalidade em treinamento").

Gates:
  F1  rotação SO(n) exata (δ_ort ≤ 1e-6) — cargo test f1;
  F2  nascimento neutro bit-a-bit — cargo test f2;
  F3  gate zona morta exata + monotonia — cargo test f3;
  F4  homeostase (gradiente a θ estrangulado com g=0) — cargo test f4;
  F6  migração compensada identidade — cargo f6;
  F7  balanço AM-GM — cargo f7;
  A1  ablação: π alta ⇒ θ aprende; π baixa ⇒ θ congelado (demo_fnh);
  A2  δ_ort do codebook da fase A mantido (rotação no treino real).
"""
import json, os, sys

def main():
    pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.insert(0, pasta)
    import khtst_rust as K

    rel = {"versao": "fnh-suite-0.7.0", "gates": {}}
    # ablação sintética controlada (mecanismo)
    fnh = K.demo_fnh()
    alta, baixa = fnh["resumo"]["punicao_alta"], fnh["resumo"]["punicao_baixa"]
    rel["gates"]["f1_so_n_exato"] = alta["delta_ort"] < 1e-6
    rel["gates"]["f3_gate_zona_morta"] = baixa["gate_final"] == 0.0
    rel["gates"]["f3_gate_abre"] = alta["gate_final"] > 0.5
    rel["gates"]["f4_homeostase_theta_congelado"] = baixa["theta_norma"] == 0.0
    rel["gates"]["f4_rotacao_aprende_com_punicao"] = alta["theta_norma"] > 0.0
    rel["ablaton"] = {"alta": alta, "baixa": baixa}

    # treino real: δ_ort do CODEBOOK TREINADO (medido pelo 63 no checkpoint
    # da fase A — rotação Stiefel EM treino real) + punição da fase C
    t70 = os.path.join(pasta, "resultados", "treino_v070.json")
    aq = os.path.join(pasta, "resultados", "arvore_quebra_v070.json")
    d_ort = None
    if os.path.exists(aq):
        with open(aq) as f:
            d_ort = json.load(f).get("quebra_cabeca_real", {}).get("delta_ort_codebook")
    if d_ort is None:
        # mede direto (o 63 roda depois se preciso — aqui executa a medição)
        ck_tok = os.path.join(pasta, "resultados", "tokenizador_conceitos.json")
        ck_ger = os.path.join(pasta, "resultados", "gerador_conceitos.json")
        if os.path.exists(ck_tok) and os.path.exists(ck_ger):
            cfg = K.Config(os.path.join(pasta, "configs", "base_rust.json"))
            qc = K.quebra_cabeca_real(cfg, ck_tok, ck_ger, n_pecas=2,
                                      n_rodadas=1, tau_c=1.1, nivel=0, seed=1)
            d_ort = qc.get("delta_ort_codebook")
    if d_ort is not None:
        rel["gates"]["a2_delta_ort_treino_real"] = d_ort < 1e-5
        rel["treino_real"] = {"delta_ort_codebook": d_ort}
    if os.path.exists(t70):
        with open(t70) as f:
            tr = json.load(f)
        pun = tr.get("fnh", {}).get("punicao_normalizada_fase_c", 0.0)
        rel["gates"]["a3_punicao_real_medida"] = 0.0 <= pun <= 1.0

    # veredito
    n_ok = sum(1 for v in rel["gates"].values() if v)
    rel["veredito"] = f"{n_ok}/{len(rel['gates'])}"
    saida = os.path.join(pasta, "resultados", "suite_fnh_v070.json")
    with open(saida, "w") as f:
        json.dump(rel, f, indent=1, ensure_ascii=False)
    print(json.dumps(rel["gates"], indent=1))
    print("VEREDITO FNH:", rel["veredito"])
    assert n_ok == len(rel["gates"]), "gate FNH falhou"

if __name__ == "__main__":
    main()