khtst-rust / src /python /pensamento_demos.rs
PowerMachine's picture
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
Raw History Blame Contribute Delete
19.3 kB
//! `python::pensamento_demos` — 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::*;
/// Classificação de erro por taxonomia (diagnóstico de refatoração).
#[pyfunction]
pub(crate) fn classificar_erro(msg: String) -> Vec<(String, String, String)> {
diagnostico::classificar_erro(&msg)
.into_iter()
.map(|(a, b, c)| (a.to_string(), b.to_string(), c.to_string()))
.collect()
}
/// Confiança de uma distribuição (T-P1): `1 − H(softmax(z))/log K`.
#[pyfunction]
pub(crate) fn confianca_de_logits(logits: Vec<f32>) -> PyResult<f64> {
let dev = candle_core::Device::Cpu;
let k = logits.len();
let t = candle_core::Tensor::from_vec(logits, (1, k), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
pensamento::confianca_de_logits(&t).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))
}
/// Projeção ridge (T-P3 — montador algébrico): `r* = (WᵀW+εI)⁻¹Wᵀr`.
#[pyfunction]
pub(crate) fn projetar_ridge(w: Vec<Vec<f64>>, r_alvo: Vec<Vec<f64>>, eps: f64) -> PyResult<Vec<Vec<f64>>> {
let dev = candle_core::Device::Cpu;
let wt = tensor_de_2d(w, &dev).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let rt = tensor_de_2d(r_alvo, &dev).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let r = pensamento::projetar_ridge(&wt, &rt, eps)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let out = r.to_vec2::<f32>().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
Ok(out.into_iter().map(|l| l.into_iter().map(|v| v as f64).collect()).collect())
}
/// Demo completa da tecnologia Pensamento: treino cooperativo das N redes
/// (item a) + ciclo d com verificador externo simulado + telemetria.
#[pyfunction]
pub(crate) fn demo_pensamento(
py: Python,
d_cond: usize,
d_saida: usize,
n_tentativas: usize,
passos_treino: usize,
limiar_conf: f64,
orcamento: usize,
semente: u64,
) -> PyResult<PyObject> {
use candle_core::Tensor;
let dev = candle_core::Device::Cpu;
crate::rng::definir_semente(semente);
let mut motor = pensamento::MotorPensamento::novo(d_cond, d_saida, n_tentativas, limiar_conf, orcamento, &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut otim = crate::treino::AdamWManual::novo(motor.vars(), 5e-3, 0.0);
let mut rng = crate::rng::RngDeterministico::novo(semente);
// dados sintéticos: alvo = função determinística não-linear de cond (d=a+b+c)
let n_dados = 256usize;
let conds: Vec<Vec<f32>> = (0..n_dados)
.map(|_| (0..d_cond).map(|_| rng.normal(0.0, 1.0) as f32).collect())
.collect();
let alvos: Vec<Vec<f32>> = conds
.iter()
.map(|c| {
(0..d_saida)
.map(|j| {
let cj = c[j % d_cond];
let ck = c[(j + 1) % d_cond];
0.5 * cj + 0.3 * cj * ck + 0.1
})
.collect()
})
.collect();
let cond_t = Tensor::from_vec(conds.into_iter().flatten().collect(), (n_dados, d_cond), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let alvo_t = Tensor::from_vec(alvos.into_iter().flatten().collect(), (n_dados, d_saida), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// item a: treino cooperativo
let mut perda_hist = Vec::new();
for passo in 0..passos_treino {
let perda = motor.perda_treino(&cond_t, &alvo_t)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
perda_hist.push(perda.to_scalar::<f32>().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))? as f64);
otim.passo(crate::treino::grads_achatados(&perda, &motor.vars())
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?);
let _ = passo;
}
// item c+d: consulta fora do padrão (OOD) — confiança baixa ⇒ Pensamento
let consulta: Vec<f32> = (0..d_cond).map(|j| 3.0 + (j as f32) * 0.1).collect();
let consulta_t = Tensor::from_vec(consulta, (d_cond,), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// verificador externo: negativo do MSE contra o alvo verdadeiro da consulta
let alvo_verdadeiro: Vec<f32> = (0..d_saida)
.map(|j| {
let cj = 3.0 + (j % d_cond) as f32 * 0.1;
let ck = 3.0 + ((j + 1) % d_cond) as f32 * 0.1;
0.5 * cj + 0.3 * cj * ck + 0.1
})
.collect();
let alvo_verd = Tensor::from_vec(alvo_verdadeiro.clone(), (d_saida,), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let verifica = |resp: &Tensor| -> f64 {
// confiança = 1/(1+10·MSE) — medível e causaL (só da resposta)
let dif = (resp.broadcast_as((1, d_saida)).unwrap() - &alvo_verd.broadcast_as((1, d_saida)).unwrap()).unwrap();
let mse = dif.sqr().unwrap().mean_all().unwrap().to_scalar::<f32>().unwrap() as f64;
1.0 / (1.0 + 10.0 * mse)
};
let mut rng2 = crate::rng::RngDeterministico::novo(semente + 1);
let res = motor.raciocinar(&consulta_t, &verifica, &mut rng2)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// linha de base SEM pensamento: uma tentativa isolada, sem agregação
let base = motor.tentativas[0].fwd(&consulta_t.broadcast_as((1, d_cond)).unwrap())
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let conf_base = verifica(&base);
let conf_pensamento = res.confianca;
let d_ = serde_json::json!({
"versao": pensamento::versao(),
"n_tentativas": n_tentativas,
"perda_treino_inicial": perda_hist.first(),
"perda_treino_final": perda_hist.last(),
"treino_aprendeu": perda_hist.last().copied().unwrap_or(f64::INFINITY) < perda_hist.first().copied().map(|p| p * 0.5).unwrap_or(f64::INFINITY),
"iteracoes_ciclo_d": res.iteracoes,
"confianca_base_1_rede": conf_base,
"confianca_pensamento": conf_pensamento,
"ganho_confianca": conf_pensamento - conf_base,
"orcamento_esgotado": res.telemetria.get("orcamento_esgotado").copied().unwrap_or(0.0),
"telemetria": res.telemetria,
"eventos_ciclo": res.trajetoria.iter().map(|e| match e {
pensamento::EventoCiclo::Planejamento { iteracao, temperatura } =>
serde_json::json!({"tipo": "planejamento", "iteracao": iteracao, "temperatura": temperatura}),
pensamento::EventoCiclo::DistribuicaoCompetencias { por_tentativa } =>
serde_json::json!({"tipo": "distribuicao", "pesos": por_tentativa}),
pensamento::EventoCiclo::RePlanejamento { motivo } =>
serde_json::json!({"tipo": "replanejamento", "motivo": motivo}),
pensamento::EventoCiclo::Resposta { confianca, iteracoes } =>
serde_json::json!({"tipo": "resposta", "confianca": confianca, "iteracoes": iteracoes}),
}).collect::<Vec<_>>(),
});
Ok(pythonize::pythonize(py, &d_)?.into())
}
/// **Ciclo d do Pensamento com o VERIFICADOR NCM** (produção, sem oráculo):
/// backbone CABEÇA TREINADA (alvo → classes) + verificador calibrado em
/// dados retidos; N tentativas agregadas; ganho medido em consultas retidas
/// EM DISTRIBUIÇÃO (onde a calibração vale — V-2) e OOD reportado à parte.
#[pyfunction]
pub(crate) fn demo_pensamento_ncm(
d_cond: usize,
d_saida: usize,
n_tentativas: usize,
passos_treino: usize,
limiar_conf: f64,
orcamento: usize,
semente: u64,
) -> PyResult<PyObject> {
Python::with_gil(|py| {
use candle_core::Tensor;
let dev = candle_core::Device::Cpu;
crate::rng::definir_semente(semente);
let mut motor = pensamento::MotorPensamento::novo(
d_cond, d_saida, n_tentativas, limiar_conf, orcamento, &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut otim = treino::AdamWManual::novo(motor.vars(), 5e-3, 0.0);
let mut rng = crate::rng::RngDeterministico::novo(semente);
// ---- dados sintéticos (item a: treino cooperativo) ----
let n_dados = 320usize;
let conds: Vec<Vec<f32>> = (0..n_dados)
.map(|_| (0..d_cond).map(|_| rng.normal(0.0, 1.0) as f32).collect())
.collect();
let alvos: Vec<Vec<f32>> = conds.iter().map(|c| {
(0..d_saida).map(|j| {
let cj = c[j % d_cond];
let ck = c[(j + 1) % d_cond];
0.5 * cj + 0.3 * cj * ck + 0.1
}).collect()
}).collect();
let mk = |c: &[f32], j: usize| -> f32 {
let cj = c[j % d_cond];
let ck = c[(j + 1) % d_cond];
0.5 * cj + 0.3 * cj * ck + 0.1
};
let cond_t = Tensor::from_vec(conds.iter().flatten().cloned().collect(), (n_dados, d_cond), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let alvo_t = Tensor::from_vec(alvos.iter().flatten().cloned().collect(), (n_dados, d_saida), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// ---- BACKBONE (cabeça treinada): alvo → classes K ----
// classe = faixa do 1º componente do alvo (aprendível, mensurável)
let k_classes = 12usize;
let classes: Vec<u32> = alvos
.iter()
.map(|a| {
let v = a[0];
let f = (((v + 2.0) / 4.0) * (k_classes as f32)).floor();
(f.clamp(0.0, (k_classes - 1) as f32)) as u32
})
.collect();
let cabeca = crate::jepa::MlpJepa::novo(d_saida, 4 * d_saida, k_classes, &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let classe_t = Tensor::from_vec(classes.clone(), (n_dados,), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut otim_cab = treino::AdamWManual::novo(cabeca.vars(), 1e-2, 0.0);
for _ in 0..200 {
let logits = cabeca.fwd(&alvo_t)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let ce = candle_nn::loss::cross_entropy(&logits, &classe_t)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
otim_cab.passo(treino::grads_achatados(&ce, &cabeca.vars())
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?);
}
// ---- VERIFICADOR calibrado em RETIDOS (metade final) ----
let n_ret = n_dados / 2;
let (alvo_ret, clas_ret) = (
alvo_t.narrow(0, n_ret, n_dados - n_ret).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?,
classe_t.narrow(0, n_ret, n_dados - n_ret).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?,
);
let logits_ret = cabeca.fwd(&alvo_ret).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut verif = verificador::VerificadorNcm::novo();
let (ece_antes, ece_depois) = verif.ajustar(&logits_ret, &clas_ret)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// logits_fn: resposta (1, d_saida) → logits do backbone (1, K)
let logits_fn = |resp: &Tensor| -> candle_core::Result<Tensor> {
cabeca.fwd(resp)
};
// ---- treino cooperativo do motor (item a) ----
let cond_tr = cond_t.narrow(0, 0, n_ret).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let alvo_tr = alvo_t.narrow(0, 0, n_ret).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut hist = Vec::new();
for _ in 0..passos_treino {
let perda = motor.perda_treino(&cond_tr, &alvo_tr)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let pv = perda.to_scalar::<f32>()
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))? as f64;
hist.push(pv);
otim.passo(treino::grads_achatados(&perda, &motor.vars())
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?);
}
// ---- consultas RETIDAS em distribuição (ganho medido AQUI) ----
let n_consultas = 8usize;
let mut confs_base = Vec::new();
let mut confs_pens = Vec::new();
let mut iteracoes = Vec::new();
for qi in 0..n_consultas {
let consulta: Vec<f32> = conds[n_ret + qi].clone();
let consulta_t = Tensor::from_vec(consulta, (d_cond,), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut rng2 = crate::rng::RngDeterministico::novo(semente + 1 + qi as u64);
let res = motor.raciocinar_ncm(&consulta_t, &verif, &logits_fn, &mut rng2)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
// base: 1 tentativa isolada, mesma verificação NCM
let base = motor.tentativas[0]
.fwd(&consulta_t.broadcast_as((1, d_cond)).unwrap()).unwrap();
let conf_base = verif.confianca_1d(&logits_fn(&base).unwrap()).unwrap();
confs_base.push(conf_base);
confs_pens.push(res.confianca);
iteracoes.push(res.iteracoes);
}
let media = |v: &[f64]| v.iter().sum::<f64>() / v.len().max(1) as f64;
let (conf_base_m, conf_pens_m) = (media(&confs_base), media(&confs_pens));
let iteracoes_media = iteracoes.iter().sum::<usize>() as f64 / iteracoes.len().max(1) as f64;
// ---- consulta OOD (reporte honesto — sem gate de ganho) ----
let consulta_ood: Vec<f32> = (0..d_cond).map(|j| 3.0 + (j as f32) * 0.1).collect();
let consulta_ood_t = Tensor::from_vec(consulta_ood, (d_cond,), &dev)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let mut rng3 = crate::rng::RngDeterministico::novo(semente + 99);
let res_ood = motor.raciocinar_ncm(&consulta_ood_t, &verif, &logits_fn, &mut rng3)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?;
let base_ood = motor.tentativas[0]
.fwd(&consulta_ood_t.broadcast_as((1, d_cond)).unwrap()).unwrap();
let conf_base_ood = verif.confianca_1d(&logits_fn(&base_ood).unwrap()).unwrap();
let _ = mk;
let d_ = serde_json::json!({
"versao": "pensamento-0.6.0-ncm",
"n_tentativas": n_tentativas,
"perda_treino_inicial": hist.first(), "perda_treino_final": hist.last(),
"treino_aprendeu": hist.last().copied() < hist.first().map(|p| p * 0.5),
"ece_verificador_antes": ece_antes, "ece_verificador_depois": ece_depois,
"temperatura_calibrada": verif.temperatura,
"iteracoes_ciclo_d_media": iteracoes_media,
"confianca_base_1_rede": conf_base_m,
"confianca_pensamento": conf_pens_m,
"ganho_confianca": conf_pens_m - conf_base_m,
"confianca_ood_base": conf_base_ood,
"confianca_ood_pensamento": res_ood.confianca,
"iteracoes_ood": res_ood.iteracoes,
"orcamento_esgotado_ood": res_ood.telemetria.get("orcamento_esgotado").copied().unwrap_or(0.0),
"verificador": "ncm-calibrado (sem oraculo)",
"gates": {
"gate_verificador_sem_oraculo": true,
"gate_calibrado": ece_depois <= ece_antes,
"gate_ganho_nao_negativo": conf_pens_m >= conf_base_m - 1e-3,
"gate_terminou": iteracoes_media <= orcamento as f64,
},
});
Ok(pythonize::pythonize(py, &d_)?.into())
})
}
/// **Autoajuste do Pensamento por telemetria (A-1..A-5) — demo:** alimenta
/// o controlador com sinais sintéticos medidos e verifica cada regra.
#[pyfunction]
pub(crate) fn demo_autoajuste(semente: u64) -> PyResult<PyObject> {
Python::with_gil(|py| {
let mut hub = telemetria::TelemetryHub::novo(None);
let mut rng = crate::rng::RngDeterministico::novo(semente);
let mut auto = controlador::AutoAjustePensamento::novo(0.5, 8, 2);
// A-1: confianças com mistura (60% altas ~0.85–0.95, 40% baixas ~0.25–0.40)
// ⇒ quantil 0.75 cai no grupo alto (posições 0.6–1.0) ≈ 0.85+0.375·0.1 ≈ 0.89
for _ in 0..200 {
let c = if rng.uniforme() < 0.6 { 0.85 + rng.uniforme() * 0.1 } else { 0.25 + rng.uniforme() * 0.15 };
auto.confs_retidas.push(c);
}
let tau = auto.ajustar_tau_c(0.25, &mut hub);
// A-3: acordos altos (0.88 ⇒ p̂ = (1+√0.76)/2 ≈ 0.936 ⇒ N = ln(20)/(2·0.436²) ≈ 7.9 ⇒ 8)
for _ in 0..32 {
auto.acordos.push(0.88);
}
let n_ajustado = auto.ajustar_n(0.05, 16, &mut hub);
// A-5: ganhos estáveis positivos (n=64 ⇒ 3º termo Bernstein ≈ 0.14 < 0.30) ⇒ gate sobe
for _ in 0..64 {
auto.ajustar_gate(0.30, 0.05, &mut hub);
}
let g_final = auto.gate_g;
// A-2: ganhos decaindo geometricamente
for k in 0..12 {
auto.ganhos_por_iteracao.push(0.25 * 0.6f64.powi(k));
}
let b_ajustado = auto.ajustar_orcamento(0.02, &mut hub);
// A-4: UCB1 com 3 braços
let mut u = controlador::Ucb1::novo(vec!["n1".into(), "n4_moe".into(), "n4".into()]);
for _ in 0..200 {
let braco = u.escolher();
let media = match braco { 0 => 0.35, 1 => 0.80, _ => 0.55 };
let r = (media + rng.normal(0.0, 0.06) as f64).clamp(0.0, 1.0);
u.registrar(braco, r);
}
let medias = u.medias();
let melhor = medias.iter().enumerate().max_by(|a, b| a.1.partial_cmp(b.1).unwrap()).map(|(i, _)| i).unwrap_or(0);
let d_ = serde_json::json!({
"versao": "autoajuste-0.6.0",
"tau_c_final": tau, "n_tentativas_final": n_ajustado,
"gate_final": g_final, "orcamento_b_final": b_ajustado,
"ajustes_auditados": hub.eventos_ajuste.len(),
"ucb1_medias": medias, "ucb1_melhor_braco": u.nomes[melhor],
"ucb1_arrependimento_medio": u.arrependimento_empirico() / 200.0,
"gates": {
"gate_a1_tau_quantil": (tau - 0.89).abs() < 0.08,
"gate_a3_n_reduzido": n_ajustado <= 8,
"gate_a5_gate_subiu": g_final > 0.0,
"gate_a2_b_finito": b_ajustado >= 1 && b_ajustado <= 16,
"gate_a4_ucb1_achou": u.nomes[melhor] == "n4_moe",
},
});
Ok(pythonize::pythonize(py, &d_)?.into())
})
}