use num_traits::Float;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Bias<T> {
value: T,
}
impl<T: Float> Bias<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn value(&self) -> T {
self.value
}
pub fn mut_value(&mut self) -> &mut T {
&mut self.value
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct InputId(usize);
impl InputId {
pub fn new(id: usize) -> Self {
Self(id)
}
pub fn as_usize(&self) -> usize {
self.0
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Input<T> {
id: InputId,
weight: T,
}
impl<T: Float> Input<T> {
pub fn new(id: InputId, weight: T) -> Self {
Self { id, weight }
}
pub fn id(&self) -> InputId {
self.id
}
pub fn weight(&self) -> T {
self.weight
}
pub fn mut_weight(&mut self) -> &mut T {
&mut self.weight
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NeuronId(usize);
impl NeuronId {
pub fn new(id: usize) -> Self {
Self(id)
}
pub fn as_usize(&self) -> usize {
self.0
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Neuron<T: Float> {
id: NeuronId,
num_inputs: usize,
weight: T,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serde", serde(default = "Default::default"))]
current_value: Option<T>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serde", serde(default = "T::zero"))]
previous_value: T,
}
impl<T: Float> Neuron<T> {
pub fn new(id: NeuronId, num_inputs: usize, weight: T) -> Self {
Self {
id,
num_inputs,
weight,
current_value: None,
previous_value: T::zero(),
}
}
pub fn id(&self) -> NeuronId {
self.id
}
pub fn num_inputs(&self) -> usize {
self.num_inputs
}
pub(crate) fn set_num_inputs(&mut self, num_inputs: usize) {
self.num_inputs = num_inputs;
}
pub fn weight(&self) -> T {
self.weight
}
pub(crate) fn mut_weight(&mut self) -> &mut T {
&mut self.weight
}
pub(crate) fn current_value(&self) -> Option<T> {
self.current_value
}
pub(crate) fn set_current_value(&mut self, value: Option<T>) {
self.current_value = value;
}
pub fn previous_value(&self) -> T {
self.previous_value
}
pub(crate) fn mut_previous_value(&mut self) -> &mut T {
&mut self.previous_value
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ForwardJumper<T> {
source_id: NeuronId,
weight: T,
}
impl<T: Float> ForwardJumper<T> {
pub fn new(source_id: NeuronId, weight: T) -> Self {
Self { source_id, weight }
}
pub fn source_id(&self) -> NeuronId {
self.source_id
}
pub fn weight(&self) -> T {
self.weight
}
pub fn mut_weight(&mut self) -> &mut T {
&mut self.weight
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RecurrentJumper<T> {
source_id: NeuronId,
weight: T,
}
impl<T: Float> RecurrentJumper<T> {
pub fn new(source_id: NeuronId, weight: T) -> Self {
Self { source_id, weight }
}
pub fn source_id(&self) -> NeuronId {
self.source_id
}
pub fn weight(&self) -> T {
self.weight
}
pub fn mut_weight(&mut self) -> &mut T {
&mut self.weight
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind"))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum Gene<T: Float> {
Bias(Bias<T>),
Input(Input<T>),
Neuron(Neuron<T>),
ForwardJumper(ForwardJumper<T>),
RecurrentJumper(RecurrentJumper<T>),
}
impl<T: Float> Gene<T> {
pub fn weight(&self) -> T {
match self {
Self::Bias(bias) => bias.value(),
Self::Input(input) => input.weight(),
Self::Neuron(neuron) => neuron.weight(),
Self::ForwardJumper(forward) => forward.weight(),
Self::RecurrentJumper(recurrent) => recurrent.weight(),
}
}
pub(crate) fn mut_weight(&mut self) -> &mut T {
match self {
Self::Bias(bias) => bias.mut_value(),
Self::Input(input) => input.mut_weight(),
Self::Neuron(neuron) => neuron.mut_weight(),
Self::ForwardJumper(forward) => forward.mut_weight(),
Self::RecurrentJumper(recurrent) => recurrent.mut_weight(),
}
}
pub fn is_bias(&self) -> bool {
matches!(self, Self::Bias(_))
}
pub fn is_input(&self) -> bool {
matches!(self, Self::Input(_))
}
pub fn is_neuron(&self) -> bool {
matches!(self, Self::Neuron(_))
}
pub fn is_forward_jumper(&self) -> bool {
matches!(self, Self::ForwardJumper(_))
}
pub fn is_recurrent_jumper(&self) -> bool {
matches!(self, Self::RecurrentJumper(_))
}
pub fn as_bias(&self) -> Option<&Bias<T>> {
if let Self::Bias(bias) = self {
Some(bias)
} else {
None
}
}
pub fn as_input(&self) -> Option<&Input<T>> {
if let Self::Input(input) = self {
Some(input)
} else {
None
}
}
pub fn as_neuron(&self) -> Option<&Neuron<T>> {
if let Self::Neuron(neuron) = self {
Some(neuron)
} else {
None
}
}
pub fn as_forward_jumper(&self) -> Option<&ForwardJumper<T>> {
if let Self::ForwardJumper(forward) = self {
Some(forward)
} else {
None
}
}
pub fn as_recurrent_jumper(&self) -> Option<&RecurrentJumper<T>> {
if let Self::RecurrentJumper(recurrent) = self {
Some(recurrent)
} else {
None
}
}
pub(crate) fn as_mut_neuron(&mut self) -> Option<&mut Neuron<T>> {
if let Self::Neuron(neuron) = self {
Some(neuron)
} else {
None
}
}
}
impl<T: Float> From<Bias<T>> for Gene<T> {
fn from(bias: Bias<T>) -> Self {
Self::Bias(bias)
}
}
impl<T: Float> From<Input<T>> for Gene<T> {
fn from(input: Input<T>) -> Self {
Self::Input(input)
}
}
impl<T: Float> From<Neuron<T>> for Gene<T> {
fn from(neuron: Neuron<T>) -> Self {
Self::Neuron(neuron)
}
}
impl<T: Float> From<ForwardJumper<T>> for Gene<T> {
fn from(forward: ForwardJumper<T>) -> Self {
Self::ForwardJumper(forward)
}
}
impl<T: Float> From<RecurrentJumper<T>> for Gene<T> {
fn from(recurrent: RecurrentJumper<T>) -> Self {
Self::RecurrentJumper(recurrent)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum NonNeuronGene<T> {
Bias(Bias<T>),
Input(Input<T>),
ForwardJumper(ForwardJumper<T>),
RecurrentJumper(RecurrentJumper<T>),
}
impl<T> From<Bias<T>> for NonNeuronGene<T> {
fn from(bias: Bias<T>) -> Self {
Self::Bias(bias)
}
}
impl<T> From<Input<T>> for NonNeuronGene<T> {
fn from(input: Input<T>) -> Self {
Self::Input(input)
}
}
impl<T> From<ForwardJumper<T>> for NonNeuronGene<T> {
fn from(forward: ForwardJumper<T>) -> Self {
Self::ForwardJumper(forward)
}
}
impl<T> From<RecurrentJumper<T>> for NonNeuronGene<T> {
fn from(recurrent: RecurrentJumper<T>) -> Self {
Self::RecurrentJumper(recurrent)
}
}
impl<T: Float> From<NonNeuronGene<T>> for Gene<T> {
fn from(gene: NonNeuronGene<T>) -> Self {
match gene {
NonNeuronGene::Bias(bias) => Self::Bias(bias),
NonNeuronGene::Input(input) => Self::Input(input),
NonNeuronGene::ForwardJumper(forward) => Self::ForwardJumper(forward),
NonNeuronGene::RecurrentJumper(recurrent) => Self::RecurrentJumper(recurrent),
}
}
}