Skip to main content

sc_neurocore_engine/bindings/
cortical_inject.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Commercial license available
3// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5// ORCID: 0009-0009-3560-0851
6// Contact: www.anulum.li | protoscience@anulum.li
7// SC-NeuroCore — cortical injection PyO3 bindings
8
9//! Python bindings for per-row-parallel cortical-column CSR injection.
10
11use numpy::{PyReadonlyArray1, PyReadwriteArray1};
12use pyo3::prelude::*;
13
14use crate::cortical_inject;
15
16/// Register single- and multi-block cortical injection kernels.
17pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
18    module.add_function(wrap_pyfunction!(py_parallel_csr_spmv_add, module)?)?;
19    module.add_function(wrap_pyfunction!(py_parallel_csr_multi_spmv_add, module)?)?;
20    Ok(())
21}
22
23/// Add one sparse cortical block multiplication to a mutable output vector.
24///
25/// `y += W @ x`, where `W` is the CSR matrix described by `indptr`, `indices`
26/// and `data`. Per-row reductions preserve SciPy-compatible arithmetic order.
27#[pyfunction]
28#[pyo3(signature = (indptr, indices, data, x, y))]
29fn py_parallel_csr_spmv_add(
30    indptr: PyReadonlyArray1<'_, i32>,
31    indices: PyReadonlyArray1<'_, i32>,
32    data: PyReadonlyArray1<'_, f64>,
33    x: PyReadonlyArray1<'_, f64>,
34    y: PyReadwriteArray1<'_, f64>,
35) -> PyResult<()> {
36    let mut y = y;
37    cortical_inject::parallel_csr_spmv_add(
38        indptr.as_slice()?,
39        indices.as_slice()?,
40        data.as_slice()?,
41        x.as_slice()?,
42        y.as_slice_mut()?,
43    );
44    Ok(())
45}
46
47/// Add several sparse cortical block multiplications in one FFI call.
48#[pyfunction]
49#[pyo3(signature = (indptrs, indices_list, data_list, xs, y))]
50fn py_parallel_csr_multi_spmv_add(
51    indptrs: Vec<PyReadonlyArray1<'_, i32>>,
52    indices_list: Vec<PyReadonlyArray1<'_, i32>>,
53    data_list: Vec<PyReadonlyArray1<'_, f64>>,
54    xs: Vec<PyReadonlyArray1<'_, f64>>,
55    y: PyReadwriteArray1<'_, f64>,
56) -> PyResult<()> {
57    let mut y = y;
58    let indptr_slices: Vec<&[i32]> = indptrs
59        .iter()
60        .map(|a| a.as_slice())
61        .collect::<Result<_, _>>()?;
62    let indices_slices: Vec<&[i32]> = indices_list
63        .iter()
64        .map(|a| a.as_slice())
65        .collect::<Result<_, _>>()?;
66    let data_slices: Vec<&[f64]> = data_list
67        .iter()
68        .map(|a| a.as_slice())
69        .collect::<Result<_, _>>()?;
70    let x_slices: Vec<&[f64]> = xs.iter().map(|a| a.as_slice()).collect::<Result<_, _>>()?;
71    cortical_inject::parallel_csr_multi_spmv_add(
72        &indptr_slices,
73        &indices_slices,
74        &data_slices,
75        &x_slices,
76        y.as_slice_mut()?,
77    );
78    Ok(())
79}