sc_neurocore_engine/bindings/
lgssm.rs1use pyo3::prelude::*;
12use pyo3::types::PyDict;
13
14use crate::lgssm;
15
16pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
18 module.add_function(wrap_pyfunction!(py_lgssm_kalman_filter, module)?)?;
19 Ok(())
20}
21
22#[pyfunction]
38#[pyo3(signature = (
39 obs_flat, controls_flat, t_len, p_dim, m_dim,
40 a_flat, b_flat, c_flat, d_flat, q_flat, r_flat,
41 mu_0, sigma_0_flat, d_dim,
42))]
43#[allow(clippy::too_many_arguments)]
44fn py_lgssm_kalman_filter<'py>(
45 py: Python<'py>,
46 obs_flat: Vec<f64>,
47 controls_flat: Vec<f64>,
48 t_len: usize,
49 p_dim: usize,
50 m_dim: usize,
51 a_flat: Vec<f64>,
52 b_flat: Vec<f64>,
53 c_flat: Vec<f64>,
54 d_flat: Vec<f64>,
55 q_flat: Vec<f64>,
56 r_flat: Vec<f64>,
57 mu_0: Vec<f64>,
58 sigma_0_flat: Vec<f64>,
59 d_dim: usize,
60) -> PyResult<Py<PyAny>> {
61 use ndarray::Array1;
62 use ndarray::Array2;
63
64 let to_2d = |flat: &[f64], rows: usize, cols: usize| -> Array2<f64> {
65 Array2::from_shape_vec((rows, cols), flat.to_vec()).expect("shape")
66 };
67 let obs = to_2d(&obs_flat, t_len, p_dim);
68 let controls = to_2d(&controls_flat, t_len, m_dim);
69 let a = to_2d(&a_flat, d_dim, d_dim);
70 let b = to_2d(&b_flat, d_dim, m_dim);
71 let c = to_2d(&c_flat, p_dim, d_dim);
72 let d = to_2d(&d_flat, p_dim, m_dim);
73 let q = to_2d(&q_flat, d_dim, d_dim);
74 let r = to_2d(&r_flat, p_dim, p_dim);
75 let mu_0_arr = Array1::from(mu_0);
76 let sigma_0 = to_2d(&sigma_0_flat, d_dim, d_dim);
77
78 let result = lgssm::kalman_filter(
79 obs.view(),
80 controls.view(),
81 a.view(),
82 b.view(),
83 c.view(),
84 d.view(),
85 q.view(),
86 r.view(),
87 mu_0_arr.view(),
88 sigma_0.view(),
89 );
90
91 let means: Vec<Vec<f64>> = (0..t_len)
93 .map(|t| (0..d_dim).map(|i| result.means[(t, i)]).collect())
94 .collect();
95 let covs: Vec<Vec<Vec<f64>>> = (0..t_len)
96 .map(|t| {
97 (0..d_dim)
98 .map(|i| (0..d_dim).map(|j| result.covariances[(t, i, j)]).collect())
99 .collect()
100 })
101 .collect();
102 let pred_means: Vec<Vec<f64>> = (0..t_len)
103 .map(|t| (0..d_dim).map(|i| result.pred_means[(t, i)]).collect())
104 .collect();
105 let pred_covs: Vec<Vec<Vec<f64>>> = (0..t_len)
106 .map(|t| {
107 (0..d_dim)
108 .map(|i| {
109 (0..d_dim)
110 .map(|j| result.pred_covariances[(t, i, j)])
111 .collect()
112 })
113 .collect()
114 })
115 .collect();
116
117 let dict = PyDict::new(py);
118 dict.set_item("means", means)?;
119 dict.set_item("covariances", covs)?;
120 dict.set_item("pred_means", pred_means)?;
121 dict.set_item("pred_covariances", pred_covs)?;
122 dict.set_item("log_likelihood", result.log_likelihood)?;
123 dict.set_item("backend", "rust")?;
124 Ok(dict.into_any().unbind())
125}