File size: 6,771 Bytes
06e4b6f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! FFI Python (PyO3) — dividida por domínio (v0.10.0, r-35 §2).

//! FFI Python (PyO3) do KHTST_RUST — todo o `#[pymodule]`, os
//! `#[pyfunction]`/`#[pyclass]` e a cola Python (conversões,
//! callbacks, demos) vivem AQUI desde a v0.9.0 (antes: lib.rs,
//! ~105 kB — crítica "God Object" do agente Qwen3.8, r-34 §5).
//! A lógica de domínio (src/*.rs) não importa pyo3: `cargo test
//! --no-default-features` executa a suíte SEM linkar o Python.
//!
//! Regra da casa mantida: nenhuma funcionalidade da superfície
//! Python foi removida — os mesmos símbolos são registrados no
//! `nucleo_rust`.

use pyo3::prelude::*;

use crate::*;

// ---- divisão SRP v0.10.0 (r-35 §2): submódulos + re-exports ----
mod calibracao;
mod demos_qwen;
mod fnh_arvore;
mod jepa_treinos;
mod moe;
mod nlp_nlg;
mod nucleo;
mod pensamento_demos;
mod som;
mod treino_fases;


// ---- itens mantidos no próprio mod.rs ----



/// Adaptador FFI→domínio (v0.9.0): embrulha um callable Python no tipo de
/// domínio `treino::CallbackTreino` — `treino.rs` não importa pyo3.
fn callback_treino_de_py(callback: Option<pyo3::Bound<'_, pyo3::PyAny>>) -> treino::CallbackTreino {
    use std::sync::Arc;
    match callback {
        None => None,
        Some(c) => {
            let f: pyo3::Py<pyo3::PyAny> = c.unbind();
            let g: Arc<dyn Fn(&serde_json::Value) + Send + Sync> =
                Arc::new(move |dados: &serde_json::Value| {
                    pyo3::Python::with_gil(|py| {
                        if let Ok(obj) = pythonize::pythonize(py, dados) {
                            let _ = f.call1(py, (obj,));
                        }
                    });
                });
            Some(g)
        }
    }
}


// ===========================================================================
// v0.5.0 — suíte SOM 4D, suíte JEPA, Pensamento, telemetria robusta
// ===========================================================================

fn tensor_de_2d(dados: Vec<Vec<f64>>, dev: &candle_core::Device) -> candle_core::Result<candle_core::Tensor> {
    let d = dados.first().map(|r| r.len()).unwrap_or(1).max(1);
    let n = dados.len();
    let flat: Vec<f32> = dados.into_iter().flat_map(|r| r.into_iter().map(|x| x as f32).collect::<Vec<_>>()).collect();
    candle_core::Tensor::from_vec(flat, (n, d), dev)
}


// ---------------------------------------------------------------------------
// v0.6.0 — verificador NCM (sem oráculo), fase C, MoE redirecionável,
// acoplador duplex e autoajuste
// ---------------------------------------------------------------------------

/// Converte matriz f64 → Tensor (n, d) F32.
fn tensor_f64_2d(v: &[Vec<f64>], dev: &candle_core::Device) -> candle_core::Result<candle_core::Tensor> {
    let (n, d) = (v.len(), v.first().map(|l| l.len()).unwrap_or(0));
    candle_core::Tensor::from_vec(v.iter().flatten().cloned().collect(), (n, d), dev)
}


fn py_err(e: candle_core::Error) -> pyo3::PyErr {
    pyo3::exceptions::PyRuntimeError::new_err(format!("{e}"))
}


#[pymodule]
fn nucleo_rust(m: &Bound<'_, PyModule>) -> PyResult<()> {
    pyo3_log::init();
    m.add_function(wrap_pyfunction!(nucleo::versao, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::info_build, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::lint_config, m)?)?;
    m.add_function(wrap_pyfunction!(treino_fases::treinar_fase_a, m)?)?;
    m.add_function(wrap_pyfunction!(treino_fases::treinar_fase_b, m)?)?;
    m.add_function(wrap_pyfunction!(treino_fases::gerar_amostras, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::verificar_mascara, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::verificar_stiefel, m)?)?;
    // v0.10.0 — checkpoints atômicos com prova de integridade
    m.add_function(wrap_pyfunction!(nucleo::checkpoint_valido, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::checkpoint_manifesto, m)?)?;
    m.add_function(wrap_pyfunction!(nucleo::sha256_arquivo, m)?)?;
    // v0.5.0 — SOM 4D / JEPA / Pensamento
    m.add_function(wrap_pyfunction!(som::treinar_som4d, m)?)?;
    m.add_function(wrap_pyfunction!(som::treinar_gng, m)?)?;
    m.add_function(wrap_pyfunction!(som::treinar_hsom, m)?)?;
    m.add_function(wrap_pyfunction!(som::demo_tsom, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::treinar_jepa, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::treinar_lejepa, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::treinar_mcjepa, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::treinar_bjepa, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::demo_sonic_moe, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::demo_replay_ssm, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::classificar_erro, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::confianca_de_logits, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::projetar_ridge, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::demo_pensamento, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::patches_2d, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::patches_serie, m)?)?;
    m.add_function(wrap_pyfunction!(jepa_treinos::grupos_pontos, m)?)?;
    // v0.6.0
    m.add_function(wrap_pyfunction!(calibracao::calibrar_verificador, m)?)?;
    m.add_function(wrap_pyfunction!(calibracao::demo_verificador_ncm, m)?)?;
    m.add_function(wrap_pyfunction!(treino_fases::treinar_fase_c, m)?)?;
    m.add_function(wrap_pyfunction!(moe::demo_moe_redirecionavel, m)?)?;
    m.add_function(wrap_pyfunction!(moe::jepa_com_moe, m)?)?;
    m.add_function(wrap_pyfunction!(moe::som_com_moe, m)?)?;
    m.add_function(wrap_pyfunction!(moe::demo_acoplador_duplo, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::demo_pensamento_ncm, m)?)?;
    m.add_function(wrap_pyfunction!(pensamento_demos::demo_autoajuste, m)?)?;
    m.add_function(wrap_pyfunction!(fnh_arvore::demo_fnh, m)?)?;
    m.add_function(wrap_pyfunction!(fnh_arvore::demo_quebra_cabeca, m)?)?;
    m.add_function(wrap_pyfunction!(fnh_arvore::quebra_cabeca_real, m)?)?;
    m.add_function(wrap_pyfunction!(nlp_nlg::demo_nlp_nlg, m)?)?;
    m.add_function(wrap_pyfunction!(som::demo_autoajuste_som, m)?)?;
    // v0.8.0 — análise/prova/teste das propostas Qwen3.8
    m.add_function(wrap_pyfunction!(demos_qwen::demo_qwen_v080, m)?)?;
    // v0.9.0 — veredito executável das críticas Qwen3.8 (r-34)
    m.add_function(wrap_pyfunction!(demos_qwen::demo_criticas_v090, m)?)?;
    m.add_class::<nucleo::BpePy>()?;
    m.add_class::<nucleo::ConfigPy>()?;
    m.add_class::<nucleo::PonteDuplaPy>()?;
    #[cfg(feature = "ponte_async")]
    m.add_class::<nucleo::PonteAsyncPy>()?;
    m.add_class::<fnh_arvore::ArvorePesosPy>()?;
    Ok(())
}