/*
    Appellation: impl_neural <module>
    Contrib: @FL03
*/
use super::Plant;

use crate::engine::{ComputationalEngine, NeuralEngine};
use crate::mem::TopoLedger;
use eryon::Tail;
use ndarray::{Array1, ArrayBase, Data, Ix1, Ix2, ScalarOperand};
use num_traits::{Float, FromPrimitive, NumAssign};

impl<T> Plant<NeuralEngine<T>>
where
    T: Float + FromPrimitive + ScalarOperand,
    NeuralEngine<T>: ComputationalEngine<usize, [usize; 3], Store = Vec<usize>>,
{
    /// adapt the weights of the engine to the given pattern
    pub fn adapt_weights_to_target(&mut self, pattern: Tail<usize, usize>) -> crate::Result<()>
    where
        T: core::iter::Sum + NumAssign,
    {
        self.engine_mut().adapt_to_target(pattern)
    }
    /// execute a transaction using learned rules provided by the given memory
    pub fn execute_with_stored(&mut self, memory: &TopoLedger<T>) -> crate::Result<()>
    where
        T: core::iter::Sum + NumAssign,
    {
        self.engine_mut().execute_with_stored(memory)
    }
    /// uses the engine to extract an action from an array
    pub fn decode_outputs_into_tail(&self, actions: Array1<T>) -> Tail<usize, usize> {
        self.engine().decode_outputs_into_tail(actions)
    }
    /// learn a sequence of actions for a number of epochs
    pub fn learn_sequence_for<U, V>(
        &mut self,
        inputs: &ArrayBase<U, Ix1>,
        targets: &ArrayBase<V, Ix1>,
        epochs: usize,
    ) -> crate::Result<T>
    where
        T: core::iter::Sum + NumAssign,
        U: Data<Elem = usize>,
        V: Data<Elem = usize>,
    {
        self.engine_mut()
            .learn_sequence_for(inputs, targets, epochs)
    }
    /// batch learn the given sequences with their targets for the given number of epochs
    pub fn learn_sequences_for<U, V>(
        &mut self,
        inputs: &ArrayBase<U, Ix2>,
        targets: &ArrayBase<V, Ix2>,
        epochs: usize,
    ) -> crate::Result<T>
    where
        T: core::iter::Sum + NumAssign,
        U: Data<Elem = usize>,
        V: Data<Elem = usize>,
    {
        self.engine_mut()
            .learn_sequences_for(inputs, targets, epochs)
    }
}
