v0.10.0: análise/prova/teste das críticas de engenharia Qwen3.8 lote 3 (r-35) — divisão SRP dos monólitos jepa/pensamento/moe/python em 26 submódulos (API estável via re-exports; 'Amdahl de compilação' refutada por experimento controlado, builds frios neutros), checkpoints atômicos SHA-256 puro FIPS 180-4 + fsync + rename + manifesto (CP-1..CP-3; correções da proposta: sem destruir estado anterior, manifesto com barreira, sem bincode/unwrap), TemperaturaInversa T-V3 (fronteira tipada da convexidade N-2; alegação compile-time corrigida), trait CamadaKhtst+CamadaHomeostatica (premissa do controlador refutada no fonte; Vec<Var>; adaptador MoeComPapel bit-a-bit), CLI Typer 75 (fachada aditiva com resume verificado por hash) — 123/123 cargo, 107/107 gates, treino real Wikipédia PT-BR com checkpoints íntegros
06e4b6f verified Download src/python/fnh_arvore.rs from PowerMachine/khtst-rust: direct link, hf CLI and curl.
- Browser
- Download file 14.3 kB
-
https://huggingface.co/PowerMachine/khtst-rust/resolve/main/src/python/fnh_arvore.rs
- Command line
-
hf download hf://PowerMachine/khtst-rust/src/python/fnh_arvore.rs
-
curl -L -o fnh_arvore.rs https://huggingface.co/PowerMachine/khtst-rust/resolve/main/src/python/fnh_arvore.rs
14.3 kB
| //! `python::fnh_arvore` — extraído do monólito na v0.10.0 | |
| //! (divisão SRP, crítica Qwen3.8 lote 3 nº 1; r-35 §2). | |
| use super::*; | |
| use super::nucleo::ConfigPy; | |
| use super::treino_fases::{carregar_gerador, carregar_tokenizador}; | |
| // --------------------------------------------------------------------------- | |
| // v0.7.0 — bindings dos módulos novos (FNH, árvore, quebra-cabeça, NLP/NLG) | |
| // --------------------------------------------------------------------------- | |
| /// Árvore de pesos indexada (arestas duplas) exposta ao Python. | |
| pub(crate) struct ArvorePesosPy { | |
| arvore: arvore_pesos::ArvorePesos, | |
| } | |
| impl ArvorePesosPy { | |
| fn nova(contagens: Option<std::collections::HashMap<String, usize>>) -> Self { | |
| let c = contagens.unwrap_or_default(); | |
| ArvorePesosPy { arvore: arvore_pesos::ArvorePesos::nova(&c) } | |
| } | |
| fn invariantes_ok(&self) -> bool { | |
| self.arvore.invariantes_ok().is_ok() | |
| } | |
| fn agregar(&mut self, metrica: &str) -> f64 { | |
| self.arvore.agregar_fundo_topo(metrica) | |
| } | |
| fn aplicar_ajuste( | |
| &mut self, | |
| no: &str, | |
| metrica: &str, | |
| delta: f64, | |
| delta_max: f64, | |
| ) -> PyResult<f64> { | |
| let idx = self | |
| .arvore | |
| .no(no) | |
| .ok_or_else(|| pyo3::exceptions::PyKeyError::new_err(format!("nó '{no}' inexistente")))?; | |
| Ok(self.arvore.aplicar_ajuste_indexado(idx, metrica, delta, delta_max)) | |
| } | |
| fn definir_metrica(&mut self, no: &str, metrica: &str, valor: f64) -> PyResult<()> { | |
| let idx = self | |
| .arvore | |
| .no(no) | |
| .ok_or_else(|| pyo3::exceptions::PyKeyError::new_err(format!("nó '{no}' inexistente")))?; | |
| self.arvore.nos[idx].metricas.insert(metrica.to_string(), valor); | |
| Ok(()) | |
| } | |
| fn metrica(&self, no: &str, metrica: &str) -> PyResult<f64> { | |
| let idx = self | |
| .arvore | |
| .no(no) | |
| .ok_or_else(|| pyo3::exceptions::PyKeyError::new_err(format!("nó '{no}' inexistente")))?; | |
| Ok(self.arvore.nos[idx].metricas.get(metrica).copied().unwrap_or(0.0)) | |
| } | |
| fn regular(&mut self, origem: &str, delta: f64, lambda: f64) -> PyResult<()> { | |
| let idx = self | |
| .arvore | |
| .no(origem) | |
| .ok_or_else(|| pyo3::exceptions::PyKeyError::new_err(format!("nó '{origem}' inexistente")))?; | |
| self.arvore.regular_topo_fundo(idx, delta, lambda); | |
| Ok(()) | |
| } | |
| fn dump(&self) -> PyResult<PyObject> { | |
| Python::with_gil(|py| { | |
| let nos: Vec<serde_json::Value> = self | |
| .arvore | |
| .nos | |
| .iter() | |
| .map(|no| { | |
| serde_json::json!({ | |
| "nome": no.nome, "ini": no.ini, "fim": no.fim, | |
| "profundidade": no.profundidade, | |
| "metricas": no.metricas, | |
| }) | |
| }) | |
| .collect(); | |
| let d = serde_json::json!({ | |
| "n_nos": self.arvore.n_nos(), | |
| "n_params": self.arvore.n_params, | |
| "invariantes_ok": self.arvore.invariantes_ok().is_ok(), | |
| "nos": nos, | |
| }); | |
| Ok(pythonize::pythonize(py, &d)?.into()) | |
| }) | |
| } | |
| } | |
| /// Demo/gate da camada FNH sobre o backbone: mede o efeito do gate de | |
| /// punição nas rotações aprendíveis (ablação: π baixa vs π alta). | |
| pub(crate) fn demo_fnh(py: Python, d_in: usize, d_out: usize, passos: usize, seed: u64) -> PyResult<PyObject> { | |
| let dev = candle_core::Device::Cpu; | |
| let mut rng = rng::RngDeterministico::novo(seed); | |
| let mut camada = fnh::CamadaFNH::nova(d_in, d_out, &dev) | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("fnh: {e}")))?; | |
| let x: Vec<f32> = (0..4 * d_in).map(|_| rng.normal_padrao() as f32).collect(); | |
| let xt = candle_core::Tensor::from_vec(x, (4, d_in), &dev) | |
| .map_err(py_err)?; | |
| camada | |
| .suavizador | |
| .calibrar(camada.base.w.as_tensor(), &xt) | |
| .map_err(py_err)?; | |
| // treino curto com punição ALTA (gate abre) vs BAIXA (gate fechado) | |
| let mut resumo = serde_json::Map::new(); | |
| for (rotulo, punicao) in [("baixa", 0.1f64), ("alta", 0.95)] { | |
| let mut cam = fnh::CamadaFNH::nova(d_in, d_out, &dev).map_err(py_err)?; | |
| // mesma semente de pesos: copia os valores | |
| let _ = &mut cam; | |
| let mut hub = telemetria::TelemetryHub::novo(None); | |
| let mut perdas = Vec::new(); | |
| for p in 0..passos { | |
| // ruído no x a cada passo (regime não-estacionário leve) | |
| let ruido: Vec<f32> = (0..4 * d_in) | |
| .map(|_| (rng.normal(0.0, 0.05)) as f32) | |
| .collect(); | |
| let xt2 = (&xt | |
| + &candle_core::Tensor::from_vec(ruido, (4, d_in), &dev).map_err(py_err)?) | |
| .map_err(py_err)?; | |
| let y = cam.forward(&xt2, punicao).map_err(py_err)?; | |
| // alvo: saída da camada base (auto-referência: regular para W) | |
| let z_ref = cam.linear_sem_bias(&xt2, cam.base.w.as_tensor()).map_err(py_err)?; | |
| let perda = (&y).sub(&z_ref).map_err(py_err)?.sqr().map_err(py_err)?.sum_all().map_err(py_err)?; | |
| perdas.push(perda.to_scalar::<f32>().map_err(py_err)? as f64); | |
| let grads = perda.backward().map_err(py_err)?; | |
| // gradiente descendente manual simples nos θ das rotações | |
| if let Some(g) = grads.get(&cam.r_wp.theta) { | |
| let gv = g.flatten_all().map_err(py_err)?.to_vec1::<f32>().map_err(py_err)?; | |
| let th = cam.r_wp.theta.as_tensor().flatten_all().map_err(py_err)?.to_vec1::<f32>().map_err(py_err)?; | |
| let novo: Vec<f32> = th.iter().zip(gv.iter()).map(|(t, g_)| t - 0.05 * g_).collect(); | |
| cam.r_wp | |
| .theta | |
| .set(&candle_core::Tensor::from_vec(novo, th.len(), &dev).map_err(py_err)?) | |
| .map_err(py_err)?; | |
| } | |
| hub.registrar("fnh_gate", cam.gate_ultimo); | |
| hub.registrar("fnh_punicao", punicao); | |
| hub.registrar("perda", perdas[p]); | |
| let _ = p; | |
| } | |
| let theta_norma: f64 = cam | |
| .r_wp | |
| .theta | |
| .as_tensor() | |
| .flatten_all() | |
| .map_err(py_err)? | |
| .to_vec1::<f32>() | |
| .map_err(py_err)? | |
| .iter() | |
| .map(|v| (*v as f64).powi(2)) | |
| .sum::<f64>() | |
| .sqrt(); | |
| let delta_ort = cam.r_wp.erro_ortogonalidade().map_err(py_err)?; | |
| resumo.insert( | |
| format!("punicao_{rotulo}"), | |
| serde_json::json!({ | |
| "gate_final": cam.gate_ultimo, | |
| "theta_norma": theta_norma, | |
| "delta_ort": delta_ort, | |
| "perda_inicial": perdas[0], | |
| "perda_final": perdas[perdas.len() - 1], | |
| }), | |
| ); | |
| } | |
| let _ = &mut camada; | |
| let d = serde_json::json!({ | |
| "versao": "fnh-0.7.0", | |
| "resumo": resumo, | |
| }); | |
| Ok(pythonize::pythonize(py, &d)?.into()) | |
| } | |
| /// **Quebra-cabeça sobre o conhecimento TREINADO REAL** (script 63): | |
| /// carrega o tokenizador (codebook do nível `nivel` — o conhecimento | |
| /// aprendido dos dados reais) e o gerador (a cabeça real como logits_fn | |
| /// do verificador); executa o protocolo completo de r-30 Q-AD. | |
| pub(crate) fn quebra_cabeca_real( | |
| cfg: &ConfigPy, | |
| caminho_tokenizador: &str, | |
| caminho_gerador: &str, | |
| n_pecas: usize, | |
| n_rodadas: usize, | |
| tau_c: f64, | |
| nivel: usize, | |
| seed: u64, | |
| ) -> PyResult<PyObject> { | |
| Python::with_gil(|py| { | |
| let dev = candle_core::Device::Cpu; | |
| crate::rng::definir_semente(seed); | |
| let mut rng = rng::RngDeterministico::novo(seed); | |
| let mut tok = tokenizador::TokenizadorConceitos::novo(&cfg.cfg, &dev) | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("tok: {e}")))?; | |
| carregar_tokenizador(&mut tok, caminho_tokenizador) | |
| .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; | |
| let mut ger = gerador::GeradorConceitos::novo(&cfg.cfg, &dev) | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("ger: {e}")))?; | |
| ger.carregar(caminho_gerador) | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("ger carregar: {e}")))?; | |
| let nivel = nivel.min(tok.quants.len().saturating_sub(1)); | |
| // conhecimento treinado REAL: codebook Stiefel (K, d_lat) | |
| let codebook = tok | |
| .quants[nivel] | |
| .codebook() | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("codebook: {e}")))?; | |
| let d_lat = codebook.dims()[1]; | |
| let k = ger.k; | |
| // δ_ort REAL do codebook treinado (rotação Stiefel em treino — A2) | |
| let delta_ort_codebook = tok.quants[nivel] | |
| .delta_ort() | |
| .unwrap_or(1.0); | |
| // logits_fn REAL: agregado (d_lat,) → proj_entrada → norm → cabeça | |
| let proj = &ger.proj_entrada; | |
| let norm = &ger.norm_entrada; | |
| let cabeca = &ger.cabeca.cabecas[nivel]; | |
| let logits_fn = move |x: &candle_core::Tensor| -> candle_core::Result<candle_core::Tensor> { | |
| let h = proj.fwd(&x.reshape((1, d_lat))?)?; | |
| let h = norm.fwd(&h)?; | |
| let lg = cabeca.fwd(&h)?; | |
| lg.reshape((k,)) | |
| }; | |
| // verificador com temperatura calibrada pela fase C quando | |
| // disponível; default 1,0 (a cota V-2 aplica-se com ECE medido) | |
| let verif = verificador::VerificadorNcm::novo(); | |
| let mut arvore = arvore_pesos::ArvorePesos::nova(&std::collections::HashMap::new()); | |
| let cfg_qc = pensamento::ConfigQuebraCabeca::novo(n_pecas, n_rodadas, tau_c); | |
| let r = pensamento::quebra_cabeca_inovar(&codebook, &verif, &logits_fn, &mut arvore, &cfg_qc, &mut rng) | |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("qc: {e}")))?; | |
| let rodadas: Vec<serde_json::Value> = r | |
| .rodadas | |
| .iter() | |
| .map(|x| { | |
| serde_json::json!({ | |
| "rodada": x.rodada, "confianca": x.confianca, | |
| "aceito": x.aceito, "delta": x.delta_aplicado, | |
| }) | |
| }) | |
| .collect(); | |
| let d_ = serde_json::json!({ | |
| "versao": "quebra-cabeca-real-0.7.0", | |
| "nivel": nivel, | |
| "delta_ort_codebook": delta_ort_codebook, | |
| "n_conceitos": codebook.dims()[0], | |
| "d_lat": d_lat, | |
| "aceitos": r.aceitos, | |
| "rejeitados": r.rejeitados, | |
| "confianca_base": r.confianca_base, | |
| "confianca_melhor": r.confianca_melhor, | |
| "telemetria": r.telemetria, | |
| "rodadas": rodadas, | |
| "arvore_invariantes": arvore.invariantes_ok().is_ok(), | |
| "punicao_no_pensamento": arvore | |
| .no("pensamento") | |
| .and_then(|i| arvore.nos[i].metricas.get("punicao").copied()) | |
| .unwrap_or(0.0), | |
| }); | |
| Ok(pythonize::pythonize(py, &d_)?.into()) | |
| }) | |
| } | |
| /// Demo/gate do quebra-cabeça sobre conceitos SINTÉTICOS estruturados | |
| /// (validação de mecanismo; a avaliação com dados reais vive no script 63). | |
| pub(crate) fn demo_quebra_cabeca( | |
| py: Python, | |
| m: usize, | |
| d: usize, | |
| n_pecas: usize, | |
| n_rodadas: usize, | |
| tau_c: f64, | |
| seed: u64, | |
| ) -> PyResult<PyObject> { | |
| let dev = candle_core::Device::Cpu; | |
| let mut rng = rng::RngDeterministico::novo(seed); | |
| // conceitos estruturados: cluster dominante +1 (média direcional) com | |
| // 25% de outliers fracos — o agregado TEM direção (sem cancelamento) | |
| let mut v = Vec::with_capacity(m * d); | |
| for i in 0..m { | |
| let centro = if i < m / 4 { 0.2 } else { 1.0 }; | |
| for j in 0..d { | |
| v.push((centro + rng.normal(0.0, 0.25)) as f32); | |
| } | |
| } | |
| let conceitos = candle_core::Tensor::from_vec(v, (m, d), &dev).map_err(py_err)?; | |
| // logits_fn ASSIMÉTRICO: projeção fixa W_proj (rotação-sensível — a | |
| // agregação simétrica seria invariante sob permutação/rotação, e o | |
| // backbone real é exatamente o avaliador NÃO-invariente da prática). | |
| let mut wv = Vec::with_capacity(d * 4); | |
| for _ in 0..d * 4 { | |
| wv.push((rng.normal_padrao() as f32) * 2.5); | |
| } | |
| let w_proj = candle_core::Tensor::from_vec(wv, (d, 4), &dev).map_err(py_err)?; | |
| // verificador com temperatura padrão | |
| let verif = verificador::VerificadorNcm::novo(); | |
| let logits_fn = |x: &candle_core::Tensor| -> candle_core::Result<candle_core::Tensor> { | |
| // logits = xᵀ·W_proj (4,) — sensível à direção do agregado | |
| x.reshape((1, d))?.matmul(&w_proj)?.reshape((4,)) | |
| }; | |
| let mut arvore = arvore_pesos::ArvorePesos::nova(&std::collections::HashMap::new()); | |
| let cfg = pensamento::ConfigQuebraCabeca::novo(n_pecas, n_rodadas, tau_c); | |
| let r = pensamento::quebra_cabeca_inovar(&conceitos, &verif, &logits_fn, &mut arvore, &cfg, &mut rng) | |
| .map_err(py_err)?; | |
| let rodadas: Vec<serde_json::Value> = r | |
| .rodadas | |
| .iter() | |
| .map(|x| { | |
| serde_json::json!({ | |
| "rodada": x.rodada, "confianca": x.confianca, | |
| "aceito": x.aceito, "delta": x.delta_aplicado, | |
| }) | |
| }) | |
| .collect(); | |
| let d_ = serde_json::json!({ | |
| "versao": "quebra-cabeca-0.7.0", | |
| "aceitos": r.aceitos, | |
| "rejeitados": r.rejeitados, | |
| "confianca_base": r.confianca_base, | |
| "confianca_melhor": r.confianca_melhor, | |
| "telemetria": r.telemetria, | |
| "rodadas": rodadas, | |
| "arvore_invariantes": arvore.invariantes_ok().is_ok(), | |
| }); | |
| Ok(pythonize::pythonize(py, &d_)?.into()) | |
| } | |