pub use native_neural_network::sphere5d::NeuronPoint;
#[derive(Debug)]
pub enum SphereStdError {
InvalidRadius,
CapacityTooSmall,
InvalidLayout,
BiasOutOfBounds,
}
impl From<native_neural_network::sphere5d::SphereError> for SphereStdError {
fn from(e: native_neural_network::sphere5d::SphereError) -> Self {
match e {
native_neural_network::sphere5d::SphereError::InvalidRadius => {
SphereStdError::InvalidRadius
}
native_neural_network::sphere5d::SphereError::CapacityTooSmall => {
SphereStdError::CapacityTooSmall
}
native_neural_network::sphere5d::SphereError::InvalidLayout => {
SphereStdError::InvalidLayout
}
native_neural_network::sphere5d::SphereError::BiasOutOfBounds => {
SphereStdError::BiasOutOfBounds
}
}
}
}
pub struct Sphere5DStd {
points: Vec<NeuronPoint>,
radius: f32,
len: usize,
}
impl Sphere5DStd {
pub fn new(capacity: usize, radius: f32) -> Result<Self, SphereStdError> {
if !radius.is_finite() || radius <= 0.0 {
return Err(SphereStdError::InvalidRadius);
}
let points = vec![NeuronPoint::default(); capacity];
Ok(Self {
points,
radius,
len: 0,
})
}
pub fn capacity(&self) -> usize {
self.points.len()
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn add_neuron(
&mut self,
layer: usize,
neuron: usize,
bias: f32,
activation: f32,
) -> Option<usize> {
let mut sphere =
match native_neural_network::sphere5d::Sphere5D::new(&mut self.points[..], self.radius)
{
Ok(s) => s,
Err(_) => return None,
};
let res = sphere.add_neuron(layer, neuron, bias, activation);
self.len = sphere.len();
res
}
pub fn nearest(&self, position: [f32; 5]) -> Option<(usize, f32)> {
if self.len == 0 {
return None;
}
let mut best_idx = 0usize;
let mut best_d2 = 0f32;
for i in 0..self.len {
let d2 = {
let a = self.points[i].position;
let mut acc = 0.0f32;
let mut j = 0usize;
while j < 5 {
let d = a[j] - position[j];
acc += d * d;
j += 1;
}
acc
};
if i == 0 || d2 < best_d2 {
best_d2 = d2;
best_idx = i;
}
}
Some((best_idx, native_neural_network::math::sqrtf(best_d2)))
}
pub fn neighbors_within(
&self,
position: [f32; 5],
max_distance: f32,
out_indices: &mut [usize],
) -> usize {
if max_distance < 0.0 || out_indices.is_empty() {
return 0;
}
let max_d2 = max_distance * max_distance;
let mut written = 0usize;
for i in 0..self.len {
if written >= out_indices.len() {
break;
}
let mut acc = 0.0f32;
let mut j = 0usize;
while j < 5 {
let d = self.points[i].position[j] - position[j];
acc += d * d;
j += 1;
}
if acc <= max_d2 {
out_indices[written] = i;
written += 1;
}
}
written
}
pub fn fill_from_network(
&mut self,
network: &crate::std::network_std::NeuralNetworkStd,
) -> Result<(), SphereStdError> {
let nn_view = native_neural_network::network::NeuralNetwork::from_parts(
&network.layers,
&network.weights,
&network.biases,
)
.ok_or(SphereStdError::InvalidLayout)?;
let mut sphere =
native_neural_network::sphere5d::Sphere5D::new(&mut self.points[..], self.radius)
.map_err(SphereStdError::from)?;
sphere
.fill_from_network(&nn_view)
.map_err(SphereStdError::from)?;
self.len = sphere.len();
Ok(())
}
}