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/pensamento_demos.rs from PowerMachine/khtst-rust: direct link, hf CLI and curl.
- Browser
- Download file 19.3 kB
-
https://huggingface.co/PowerMachine/khtst-rust/resolve/main/src/python/pensamento_demos.rs
- Command line
-
hf download hf://PowerMachine/khtst-rust/src/python/pensamento_demos.rs
-
curl -L -o pensamento_demos.rs https://huggingface.co/PowerMachine/khtst-rust/resolve/main/src/python/pensamento_demos.rs
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). | |
| 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`. | |
| 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`. | |
| 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. | |
| 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. | |
| 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. | |
| 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()) | |
| }) | |
| } | |