//! PROVAS EXECUTÁVEIS (gates de integração) do KHTST_RUST v0.7.0. //! //! Regra da casa (r-08 §1): *contar a estrutura não é verificar a função* — //! toda verificação precisa de um `assert` que FALHE se o invariante quebrar. //! Os 54 testes unitários vivem inline em cada módulo; ESTE arquivo contém os //! GATES DE INTEGRAÇÃO entre módulos (vazamentos, paridades, neutralidades //! e os gates novos da v0.7.0: FNH, árvore de pesos, quebra-cabeça, NLP/NLG). //! //! Histórico: os gates G1/G2/G4/G10 da v0.3.0 migraram para a suíte Python //! (V4 máscara 0 vazamentos, V10 paridade NFE=L) e para testes inline dos //! módulos (ssd, quantizador, mascaras); os gates G9/G12 da mistura de planos //! tornaram-se obsoletos com a remoção da CabecaMistura (v0.4.0 — a mistura //! vive hoje no verificador, ver F_mistura_verificador.md e verificador.rs). //! //! | gate | o que prova | módulos | //! |---|---|---| //! | G5 | nascimento neutro do FiLM (γ=β=ξ=ζ=0 ⇒ identidade) | gerador+tronco | //! | M8 | PCGrad não-piora (⟨g_comb, g_i⟩ ≥ 0 ∀i) | perdas+treino | //! | G13 | FNH: R∈SO(n) exato + neutralidade com punição baixa | fnh | //! | G14 | FNH: gate de punição monotoneidade + migração de escala idempotente | fnh | //! | G15 | árvore de pesos: partição de índices + simetria das arestas duplas | arvore_pesos | //! | G16 | árvore: agregação fundo-topo = soma global (indução na árvore) | arvore_pesos | //! | G17 | quebra-cabeça: todo aceito tem confiança ≥ τ_c (soundness V-2) | pensamento+verificador | //! | G18 | NLP/NLG: nascimento neutro (Δ=0 bit-a-bit) | nlp+nlg | //! | G19 | decodificador especulativo: inocuidade (distribuição preservada) | nlg | //! | G20 | rotação no Pensamento: ortogonalidade preservada pós-ciclo | pensamento+stiefel | use candle_core::{Device, Result, Tensor}; /// G5 — NASCIMENTO NEUTRO: com o tronco recém-construído (γ=0, β=0, ξ=0, /// ζ=0), aplicar_film é a IDENTIDADE bit-a-bit, qualquer que seja o resumo. #[test] fn gate_g5_nascimento_neutro_film() -> Result<()> { use khtst_rust::config::ConfigKhtst; use khtst_rust::gerador::GeradorConceitos; let mut cfg = ConfigKhtst::default(); cfg.modelo.vocab = 64; cfg.modelo.d_modelo = 32; cfg.modelo.n_camadas = 2; cfg.modelo.n_cabecas = 4; cfg.modelo.d_ff = 64; cfg.modelo.comprimento_ctx = 8; cfg.ncm.niveis = vec![2, 4, 8]; cfg.ncm.d_lat = 8; cfg.ncm.k_por_nivel = 8; cfg.ncm.ativo = true; cfg.modelo.mtp.ativo = false; cfg.validar().expect("config do gate G5"); let dev = Device::Cpu; let ger = GeradorConceitos::novo(&cfg, &dev)?; let x = Tensor::randn(0f32, 1f32, (2, 4, cfg.modelo.d_modelo), &dev)?; let resumo = Tensor::randn(0f32, 1f32, (2, cfg.modelo.d_modelo), &dev)?; for nivel in 1..=cfg.l_niveis() { let y = ger.tronco.aplicar_film(&x, &resumo, nivel)?; let dif = (&x - &y)?.abs()?.max_all()?.to_scalar::()?; assert_eq!(dif, 0.0, "G5: FiLM deve ser identidade no nascimento (nível {nivel})"); } Ok(()) } /// M8 — PCGrad projeta contra os gradientes ORIGINAIS (invariante de /// não-piora: ⟨g_combinado, g_i⟩ ≥ 0 para toda perda i). #[test] fn gate_m8_pcgrad_nao_piora() { let g1 = vec![Some(vec![1.0f32]), Some(vec![-2.0])]; let g2 = vec![Some(vec![-1.0f32]), Some(vec![0.5])]; let combinado = khtst_rust::treino::pcgrad_achatado(vec![g1.clone(), g2.clone()]); let ip = |a: &Vec>>, b: &Vec>>| -> f64 { let mut s = 0f64; for (x, y) in a.iter().zip(b.iter()) { if let (Some(x), Some(y)) = (x, y) { s += x.iter().zip(y.iter()).map(|(p, q)| *p as f64 * *q as f64).sum::(); } } s }; let ip1 = ip(&combinado, &g1); let ip2 = ip(&combinado, &g2); assert!(ip1 >= -1e-9, "⟨g, g1⟩ = {ip1} ≥ 0 (não-piora)"); assert!(ip2 >= -1e-9, "⟨g, g2⟩ = {ip2} ≥ 0 (não-piora)"); }