use pyo3::prelude::*;
#[pyfunction]
#[pyo3(signature = (src_area_id, dst_area_id, src_neuron_id, src_dimensions, dst_dimensions, neuron_location, transpose=None, project_last_layer_of=None))]
fn py_syn_projector(
src_area_id: &str,
dst_area_id: &str,
src_neuron_id: u64,
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
neuron_location: (i32, i32, i32),
transpose: Option<(usize, usize, usize)>,
project_last_layer_of: Option<usize>,
) -> PyResult<Vec<(i32, i32, i32)>> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
let result = crate::connectivity::rules::syn_projector(
src_area_id,
dst_area_id,
src_neuron_id,
src_dimensions,
dst_dimensions,
loc_u32,
transpose,
project_last_layer_of,
);
match result {
Ok(positions) => Ok(positions.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect()),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Rust syn_projector error: {}",
e
))),
}
}
#[pyfunction]
#[pyo3(signature = (src_area_id, dst_area_id, neuron_ids, neuron_locations, src_dimensions, dst_dimensions, transpose=None, project_last_layer_of=None))]
fn py_syn_projector_batch(
src_area_id: &str,
dst_area_id: &str,
neuron_ids: Vec<u64>,
neuron_locations: Vec<(i32, i32, i32)>,
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
transpose: Option<(usize, usize, usize)>,
project_last_layer_of: Option<usize>,
) -> PyResult<Vec<Vec<(i32, i32, i32)>>> {
let locs_u32: Vec<(u32, u32, u32)> = neuron_locations.iter()
.map(|(x, y, z)| (*x as u32, *y as u32, *z as u32))
.collect();
let result = crate::connectivity::rules::syn_projector_batch(
src_area_id,
dst_area_id,
&neuron_ids,
&locs_u32,
src_dimensions,
dst_dimensions,
transpose,
project_last_layer_of,
);
match result {
Ok(position_lists) => Ok(position_lists.iter()
.map(|positions| positions.iter()
.map(|(x, y, z)| (*x as i32, *y as i32, *z as i32))
.collect())
.collect()),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
"Rust syn_projector_batch error: {}",
e
))),
}
}
#[pyfunction]
fn py_syn_block_connection(
src_area_id: &str,
dst_area_id: &str,
neuron_location: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
scaling_factor: i32,
) -> PyResult<(i32, i32, i32)> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
let scale_u32 = scaling_factor as u32;
match crate::connectivity::rules::syn_block_connection(
src_area_id, dst_area_id, loc_u32, src_dimensions, dst_dimensions, scale_u32
) {
Ok((x, y, z)) => Ok((x as i32, y as i32, z as i32)),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("{}", e))),
}
}
#[pyfunction]
fn py_syn_expander(
src_area_id: &str,
dst_area_id: &str,
neuron_location: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
) -> PyResult<(i32, i32, i32)> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
match crate::connectivity::rules::syn_expander(
src_area_id, dst_area_id, loc_u32, src_dimensions, dst_dimensions
) {
Ok((x, y, z)) => Ok((x as i32, y as i32, z as i32)),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("{}", e))),
}
}
#[pyfunction]
fn py_syn_expander_batch(
src_area_id: &str,
dst_area_id: &str,
neuron_locations: Vec<(i32, i32, i32)>,
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
) -> PyResult<Vec<(i32, i32, i32)>> {
let locs_u32: Vec<(u32, u32, u32)> = neuron_locations.iter()
.map(|(x, y, z)| (*x as u32, *y as u32, *z as u32))
.collect();
match crate::connectivity::rules::syn_expander_batch(
src_area_id, dst_area_id, &locs_u32, src_dimensions, dst_dimensions
) {
Ok(positions) => Ok(positions.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect()),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("{}", e))),
}
}
#[pyfunction]
fn py_syn_reducer_x(
src_area_id: &str,
dst_area_id: &str,
neuron_location: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
dst_y_index: i32,
dst_z_index: i32,
) -> PyResult<Vec<(i32, i32, i32)>> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
match crate::connectivity::rules::syn_reducer_x(
src_area_id, dst_area_id, loc_u32, src_dimensions, dst_dimensions, dst_y_index as u32, dst_z_index as u32
) {
Ok(positions) => Ok(positions.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect()),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("{}", e))),
}
}
#[pyclass]
struct PyMortonSpatialHash {
inner: std::sync::Arc<crate::spatial::MortonSpatialHash>,
}
#[pymethods]
impl PyMortonSpatialHash {
#[new]
fn new() -> Self {
Self {
inner: std::sync::Arc::new(crate::spatial::MortonSpatialHash::new()),
}
}
fn add_neuron(&self, cortical_area: String, x: u32, y: u32, z: u32, neuron_id: u64) -> bool {
self.inner.add_neuron(cortical_area, x, y, z, neuron_id)
}
fn get_neuron_at_coordinate(&self, cortical_area: &str, x: u32, y: u32, z: u32) -> Option<u64> {
self.inner.get_neuron_at_coordinate(cortical_area, x, y, z)
}
fn get_neurons_at_coordinate(&self, cortical_area: &str, x: u32, y: u32, z: u32) -> Vec<u64> {
self.inner.get_neurons_at_coordinate(cortical_area, x, y, z)
}
fn get_neurons_in_region(
&self,
cortical_area: &str,
x1: u32, y1: u32, z1: u32,
x2: u32, y2: u32, z2: u32,
) -> Vec<u64> {
self.inner.get_neurons_in_region(cortical_area, x1, y1, z1, x2, y2, z2)
}
fn get_neuron_position(&self, neuron_id: u64) -> Option<(String, u32, u32, u32)> {
self.inner.get_neuron_position(neuron_id)
}
fn remove_neuron(&self, neuron_id: u64) -> bool {
self.inner.remove_neuron(neuron_id)
}
fn clear(&self) {
self.inner.clear();
}
fn get_stats(&self) -> PyResult<PyObject> {
Python::with_gil(|py| {
let stats = self.inner.get_stats();
let dict = pyo3::types::PyDict::new_bound(py);
dict.set_item("total_areas", stats.total_areas)?;
dict.set_item("total_neurons", stats.total_neurons)?;
dict.set_item("total_occupied_positions", stats.total_occupied_positions)?;
Ok(dict.to_object(py))
})
}
}
#[pyfunction]
fn py_morton_encode_3d(x: u32, y: u32, z: u32) -> PyResult<u64> {
use crate::spatial::morton_encode_3d;
Ok(morton_encode_3d(x, y, z))
}
#[pyfunction]
fn py_morton_decode_3d(morton_code: u64) -> PyResult<(u32, u32, u32)> {
use crate::spatial::morton_decode_3d;
Ok(morton_decode_3d(morton_code))
}
#[pyfunction]
fn py_apply_vector_offset(
src_position: (i32, i32, i32),
vector: (i32, i32, i32),
morphology_scalar: f32,
dst_dimensions: (usize, usize, usize),
) -> PyResult<Option<(i32, i32, i32)>> {
let src_u32 = (src_position.0 as u32, src_position.1 as u32, src_position.2 as u32);
Ok(
crate::connectivity::rules::apply_vector_offset(src_u32, vector, morphology_scalar, dst_dimensions)
.map(|(x, y, z)| (x as i32, y as i32, z as i32)),
)
}
#[pyfunction]
fn py_match_vectors_batch(
src_positions: Vec<(i32, i32, i32)>,
vector: (i32, i32, i32),
morphology_scalar: f32,
dst_dimensions: (usize, usize, usize),
) -> PyResult<Vec<(i32, i32, i32)>> {
let srcs_u32: Vec<(u32, u32, u32)> = src_positions.iter()
.map(|(x, y, z)| (*x as u32, *y as u32, *z as u32))
.collect();
match crate::connectivity::rules::match_vectors_batch(
&srcs_u32, vector, morphology_scalar, dst_dimensions
) {
Ok(positions) => Ok(positions.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect()),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!("{}", e))),
}
}
#[pyfunction]
fn py_match_patterns(
src_coordinate: (i32, i32, i32),
patterns: Vec<((i32, i32, i32), (i32, i32, i32))>,
src_dimensions: (usize, usize, usize),
dst_dimensions: (usize, usize, usize),
) -> PyResult<Vec<(i32, i32, i32)>> {
use crate::connectivity::rules::patterns::{PatternElement, match_patterns_batch};
let src_u32 = (src_coordinate.0 as u32, src_coordinate.1 as u32, src_coordinate.2 as u32);
let parsed_patterns: Vec<_> = patterns.iter().map(|(src, dst)| {
let src_pattern = (
PatternElement::from_int(src.0),
PatternElement::from_int(src.1),
PatternElement::from_int(src.2),
);
let dst_pattern = (
PatternElement::from_int(dst.0),
PatternElement::from_int(dst.1),
PatternElement::from_int(dst.2),
);
(src_pattern, dst_pattern)
}).collect();
let results = match_patterns_batch(
src_u32,
&parsed_patterns,
src_dimensions,
dst_dimensions,
);
Ok(results.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect())
}
#[pyfunction]
fn py_find_source_coordinates(
src_pattern: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
) -> PyResult<Vec<(i32, i32, i32)>> {
use crate::connectivity::rules::patterns::{PatternElement, find_source_coordinates};
let pattern = (
PatternElement::from_int(src_pattern.0),
PatternElement::from_int(src_pattern.1),
PatternElement::from_int(src_pattern.2),
);
let results = find_source_coordinates(&pattern, src_dimensions);
Ok(results.iter().map(|(x, y, z)| (*x as i32, *y as i32, *z as i32)).collect())
}
#[pyfunction]
fn py_syn_randomizer(dst_dimensions: (usize, usize, usize)) -> PyResult<(i32, i32, i32)> {
let (x, y, z) = crate::connectivity::rules::syn_randomizer(dst_dimensions);
Ok((x as i32, y as i32, z as i32))
}
#[pyfunction]
fn py_syn_lateral_pairs_x(
neuron_location: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
) -> PyResult<Option<(i32, i32, i32)>> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
Ok(crate::connectivity::rules::syn_lateral_pairs_x(loc_u32, src_dimensions)
.map(|(x, y, z)| (x as i32, y as i32, z as i32)))
}
#[pyfunction]
fn py_syn_last_to_first(
neuron_location: (i32, i32, i32),
src_dimensions: (usize, usize, usize),
) -> PyResult<Option<(i32, i32, i32)>> {
let loc_u32 = (neuron_location.0 as u32, neuron_location.1 as u32, neuron_location.2 as u32);
Ok(crate::connectivity::rules::syn_last_to_first(loc_u32, src_dimensions)
.map(|(x, y, z)| (x as i32, y as i32, z as i32)))
}
#[pymodule]
fn feagi_brain_development(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(py_syn_projector, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_projector_batch, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_block_connection, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_expander, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_expander_batch, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_reducer_x, m)?)?;
m.add_function(wrap_pyfunction!(py_apply_vector_offset, m)?)?;
m.add_function(wrap_pyfunction!(py_match_vectors_batch, m)?)?;
m.add_function(wrap_pyfunction!(py_match_patterns, m)?)?;
m.add_function(wrap_pyfunction!(py_find_source_coordinates, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_randomizer, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_lateral_pairs_x, m)?)?;
m.add_function(wrap_pyfunction!(py_syn_last_to_first, m)?)?;
m.add_class::<PyMortonSpatialHash>()?;
m.add_function(wrap_pyfunction!(py_morton_encode_3d, m)?)?;
m.add_function(wrap_pyfunction!(py_morton_decode_3d, m)?)?;
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
m.add("__doc__", "FEAGI BDU - High-performance Brain Development Utilities")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ffi_compatibility() {
let result = py_syn_projector(
"src",
"dst",
42,
(128, 128, 3),
(128, 128, 1),
(64, 64, 1),
None,
None,
);
assert!(result.is_ok());
}
}