sc_neurocore_engine/bindings/
ollivier_ricci.rs1use pyo3::exceptions::PyValueError;
12use pyo3::prelude::*;
13
14use crate::topology::{self, CurvatureError};
15
16pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
18 module.add_function(wrap_pyfunction!(py_ollivier_ricci_curvature, module)?)?;
19 Ok(())
20}
21
22fn curvature_error_message(error: CurvatureError) -> &'static str {
23 match error {
24 CurvatureError::BadShape => "knm must be a square coupling matrix with at least one node",
25 CurvatureError::BadValue => "knm must contain only finite, non-negative values",
26 CurvatureError::BadIndex => "node index out of range for coupling graph",
27 CurvatureError::Infeasible => "transport problem is infeasible",
28 }
29}
30
31fn map_curvature_error(error: CurvatureError) -> PyErr {
32 PyValueError::new_err(curvature_error_message(error))
33}
34
35#[pyfunction]
45#[pyo3(signature = (knm_flat, n, i, j))]
46fn py_ollivier_ricci_curvature(knm_flat: Vec<f64>, n: usize, i: usize, j: usize) -> PyResult<f64> {
47 topology::ollivier_ricci_curvature(&knm_flat, n, i, j).map_err(map_curvature_error)
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn error_messages_preserve_the_public_contract() {
56 assert_eq!(
57 curvature_error_message(CurvatureError::BadShape),
58 "knm must be a square coupling matrix with at least one node"
59 );
60 assert_eq!(
61 curvature_error_message(CurvatureError::BadValue),
62 "knm must contain only finite, non-negative values"
63 );
64 assert_eq!(
65 curvature_error_message(CurvatureError::BadIndex),
66 "node index out of range for coupling graph"
67 );
68 assert_eq!(
69 curvature_error_message(CurvatureError::Infeasible),
70 "transport problem is infeasible"
71 );
72 }
73}