/*
    Appellation: neural <module>
    Contrib: @FL03
*/
use super::{NeuralController, NeuralFeatures};

use crate::engine::{ComputationalEngine, Engine, RawEngine};
use crate::mem::TopoLedger;
use cnc::{ReLU, Sigmoid};
use eryon::{Direction, Head, State, Tail};
use ndarray::{Array1, Array2, ArrayBase, Data, Ix1, Ix2, ScalarOperand, s};
use num_traits::{Float, FromPrimitive, NumAssign};

fn _direction_to_idx(direction: Direction) -> usize {
    match direction {
        Direction::Left => 0,
        Direction::Stay => 1,
        Direction::Right => 2,
    }
}

/// A Neural Turing Machine (NTM) is a type of recurrent neural network that can learn to
/// perform algorithmic tasks by interacting with an external memory. The NTM consists of a
/// controller network that interacts with a memory matrix using attention mechanisms.
/// Internally, the controller is a shallow feed-forward neural network capable of processing
/// encoded inputs and producing outputs that determine the next state, symbol, and direction
/// of the machine.
#[derive(Clone, Debug)]
pub struct NeuralEngine<T = f32> {
    pub(crate) alphabet: [usize; 3],
    pub(crate) controller: NeuralController<T>,
    pub(crate) memory: Array2<T>,
    pub(crate) position: usize,
    pub(crate) state: State<usize>,
    pub(crate) tape: Vec<usize>,
    // Read/write heads with attention weights
    pub(crate) read_weights: Array1<T>,
    /// Write weights
    pub(crate) write_weights: Array1<T>,
    // Learning parameters
    pub(crate) learning_rate: T,
}

impl<T> NeuralEngine<T> {
    pub const STATES: usize = 2;
    pub const SYMBOLS: usize = 3;

    pub fn new(alphabet: [usize; 3], State(initial_state): State<usize>) -> Self
    where
        T: Clone + Default + FromPrimitive,
    {
        let controller = NeuralController::new();
        let memory_size = controller.features().dim_memory();
        Self {
            alphabet,
            controller,
            memory: Array2::default(memory_size),
            position: 0,
            state: State(initial_state),
            tape: Vec::new(),
            read_weights: Array1::default(memory_size.0),
            write_weights: Array1::default(memory_size.0),
            learning_rate: T::from_f64(0.01).unwrap(),
        }
    }
    /// returns an immutable reference to the alphabet
    pub const fn alphabet(&self) -> &[usize; 3] {
        &self.alphabet
    }
    /// returns an immutable reference to the controller
    pub const fn controller(&self) -> &NeuralController<T> {
        &self.controller
    }
    /// returns a mutable reference to the controller
    pub fn controller_mut(&mut self) -> &mut NeuralController<T> {
        &mut self.controller
    }
    /// returns a copy of the engine controller's features
    pub const fn features(&self) -> NeuralFeatures {
        self.controller().features()
    }
    /// returns a mutable reference to the engine controller's features
    pub fn features_mut(&mut self) -> &mut NeuralFeatures {
        self.controller_mut().features_mut()
    }
    /// returns an immutable reference to the memory of the machine
    pub const fn memory(&self) -> &Array2<T> {
        &self.memory
    }
    /// returns a mutable reference to the memory of the machine
    pub fn memory_mut(&mut self) -> &mut Array2<T> {
        &mut self.memory
    }
    /// returns the current position of the head of the machine
    pub const fn position(&self) -> usize {
        self.position
    }
    /// returns a mutable reference to the position of the head of the machine
    pub fn position_mut(&mut self) -> &mut usize {
        &mut self.position
    }
    /// returns a copy of the state of the machine
    pub const fn state(&self) -> State<usize> {
        self.state
    }
    /// returns a mutable reference to the state of the machine
    pub fn state_mut(&mut self) -> &mut State<usize> {
        &mut self.state
    }
    /// returns an immutable reference to the tape of the machine
    pub const fn tape(&self) -> &Vec<usize> {
        &self.tape
    }
    /// returns a mutable reference to the tape of the machine
    pub fn tape_mut(&mut self) -> &mut Vec<usize> {
        &mut self.tape
    }
    /// set the current position of the machine
    pub fn set_position(&mut self, position: usize) {
        self.position = position;
    }
    /// set the state of the machine
    pub fn set_state(&mut self, state: State<usize>) {
        self.state = state;
    }
    /// set the tape of the machine
    pub fn set_tape<I>(&mut self, iter: I)
    where
        I: IntoIterator<Item = usize>,
    {
        self.tape = Vec::from_iter(iter);
    }
    /// returns the head of the machine
    pub fn head(&self) -> Head<usize, usize> {
        Head::new(self.state, self.tape[self.position])
    }
    /// inititalize the controller and return a new instance with the randomized parameters
    #[cfg(feature = "rand")]
    pub fn init(self) -> Self
    where
        T: Float + FromPrimitive + rand_distr::uniform::SampleUniform,
        rand_distr::StandardNormal: rand_distr::Distribution<T>,
    {
        Self {
            controller: self.controller.init(),
            ..self
        }
    }
    /// clear's the contents of the tape and resets the position of the head back to 0
    pub fn reset(&mut self) {
        self.tape.clear();
        self.reset_position();
    }
    /// reset the position of the head of the machine to `0`
    pub fn reset_position(&mut self) {
        self.position = 0;
    }
}

impl<T> NeuralEngine<T>
where
    T: Float + FromPrimitive + ScalarOperand,
    NeuralEngine<T>: ComputationalEngine<usize, [usize; 3], Store = Vec<usize>>,
{
    /// adapt the engine's weights to the target tail (pattern)
    pub fn adapt_to_target(&mut self, tail: Tail<usize, usize>) -> crate::Result<()>
    where
        T: NumAssign + core::iter::Sum,
    {
        // Read current symbol
        let cur_symbol = if self.position < self.tape.len() {
            self.tape[self.position]
        } else {
            0
        };

        // encode the symbol into input for the controller
        let controller_input = self.encode_input_symbol(cur_symbol);
        // forward the input through the controller to get a prediction
        let current_output = self.forward(&controller_input)?;
        // convert the tail to a target tensor
        let target_output = self.tail_to_targets(tail);
        // compute the error
        let error = &target_output - &current_output;
        // initialize a buffer to store layer activations
        let mut activations = Vec::new();
        // forward the input through the first layer
        let mut fwd = self.controller().input().forward(&controller_input)?.relu();
        activations.push(fwd.clone());
        // forward the input through the hidden layer
        fwd = self.controller().hidden().forward(&fwd)?.relu();
        activations.push(fwd.clone());
        // forward the input through the output layer
        fwd = self.controller().output().forward(&fwd)?.sigmoid();
        activations.push(fwd.clone());

        // compute the magnitude of the error (L2 Norm)
        let error_magnitude = error.pow2().sum().sqrt();
        // adapt the learning rate based on the magnitude of the error
        let adaptive_lr = if error_magnitude > T::from(0.5).unwrap() {
            self.learning_rate * T::from(1.5).unwrap() // Boost learning for large errors
        } else {
            self.learning_rate
        };
        // Calculate error gradient for hidden layer - prepare it before updating weights
        let hidden_error = &error * self.controller().output_weights().t().relu_derivative();

        // use blocks to avoid referencing issues
        {
            // start with the output layer
            let delta = &error * activations.last().cloned().unwrap().sigmoid_derivative();
            self.controller_mut()
                .output_mut()
                .backward(&activations[1], &delta, adaptive_lr)?;
        }
        // backpropagate the hidden layer(s)
        {
            let delta = hidden_error.dot(&activations[1].relu_derivative());
            self.controller_mut()
                .hidden_mut()
                .backward(&activations[0], &delta, adaptive_lr)?;
        }
        // then backpropagate the input layer
        {
            let lr = adaptive_lr * T::from(0.5).unwrap();
            let delta = hidden_error.dot(&activations[1].relu_derivative());
            self.controller_mut()
                .input_mut()
                .backward(&controller_input, &delta, lr)?;
        }

        // if necessary, update the attention mechanism
        if error_magnitude > T::from(0.3).unwrap() {
            self.update_attention(controller_input);
        }
        Ok(())
    }
    /// extract a tail (next_state, next_symbol, direction) from controller output
    pub fn decode_outputs_into_tail(&self, output: Array1<T>) -> Tail<usize, usize> {
        let output_len = output.len();

        // Split the output vector into segments for different actions

        // State determination (first part of output)
        // Use softmax-like approach to select a state
        let num_states = 2; // Assuming 2 possible states
        let state_end = core::cmp::min(num_states, output_len);
        let state_probs = output.slice(s![0..state_end]).to_owned();

        // Find the index with the highest activation for state
        let next_state = state_probs
            .iter()
            .enumerate()
            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal))
            .map(|(i, _)| i)
            .unwrap_or(0);

        // Symbol determination (middle part of output)
        let symbol_start = state_end;
        let symbol_end = core::cmp::min(symbol_start + self.alphabet.len(), output_len);
        let symbol_probs = if symbol_end > symbol_start {
            output.slice(s![symbol_start..symbol_end]).to_owned()
        } else {
            Array1::<T>::zeros(1)
        };

        // Find the index with highest activation for symbol
        let symbol_idx = symbol_probs
            .iter()
            .enumerate()
            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal))
            .map(|(i, _)| i)
            .unwrap_or(0);

        // Map to actual symbol in alphabet
        let next_symbol = if symbol_idx < self.alphabet.len() {
            self.alphabet[symbol_idx]
        } else {
            self.alphabet[0] // Default to first symbol
        };

        // Direction determination (last part of output)
        // Use 3 values for Left, Stay, Right
        let dir_start = symbol_end;
        let dir_end = core::cmp::min(dir_start + 3, output_len);
        let dir_probs = if dir_end > dir_start {
            output.slice(s![dir_start..dir_end]).to_owned()
        } else {
            Array1::zeros(3)
        };

        // Find index with highest activation for direction
        let dir_idx = dir_probs
            .iter()
            .enumerate()
            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal))
            .map(|(i, _)| i)
            .unwrap_or(1); // Default to Stay (middle value)

        let direction = match dir_idx {
            0 => Direction::Left,
            1 => Direction::Stay,
            _ => Direction::Right,
        };

        Tail::new(direction, State(next_state), next_symbol)
    }
    /// determine the best direction toDetermine best direction to reach expected symbol based on current state and tape
    pub fn determine_best_direction(&self, expected: usize) -> Direction {
        // Check current position in the tape
        let current_symbol = if self.position < self.tape.len() {
            self.tape[self.position]
        } else {
            0 // Default empty symbol
        };

        // If we're already at the expected symbol, stay
        if current_symbol == expected {
            return Direction::Stay;
        }

        // Check left and right positions to find the expected symbol
        let left_has_expected = self.position > 0
            && self.position - 1 < self.tape.len()
            && self.tape[self.position - 1] == expected;

        let right_has_expected =
            self.position + 1 < self.tape.len() && self.tape[self.position + 1] == expected;

        // If expected symbol is to the left, go left
        if left_has_expected {
            return Direction::Left;
        }

        // If expected symbol is to the right, go right
        if right_has_expected {
            return Direction::Right;
        }

        // If we can't find the expected symbol, use a heuristic:
        // - If we're closer to the left end, try moving right
        // - If we're closer to the right end, try moving left
        // - Otherwise, just stay
        if self.position < self.tape.len() / 2 {
            Direction::Right
        } else if self.position > 0 {
            Direction::Left
        } else {
            Direction::Stay
        }
    }
    /// Prepares the input for the controller network by combining state and symbol information
    pub fn encode_input_symbol(&self, symbol: usize) -> Array1<T> {
        let mut input = Array1::<T>::zeros(self.controller.inputs());

        // One-hot encode the current symbol (assuming symbol values are within alphabet size)
        let symbol_idx = self.alphabet.iter().position(|&s| s == symbol).unwrap_or(0);

        // First part of the input is the one-hot encoded symbol
        if symbol_idx < self.controller.inputs() {
            input[symbol_idx] = T::one();
        }

        // Encode the current state as part of the input
        // Use bit representation of state value spread across input vector
        let state_val = *self.state();
        for i in 0..core::cmp::min(32, self.controller.inputs() - 3) {
            if (state_val & (1 << i)) != 0 {
                let idx = 3 + i;
                if idx < self.controller.inputs() {
                    input[idx] = T::one();
                }
            }
        }

        // Add memory read vector to the input
        let read_content = self.read_memory();
        let dim_inputs = self.controller.inputs();
        let memory_start = core::cmp::min(dim_inputs.wrapping_sub(read_content.len()), dim_inputs);
        for (i, &val) in read_content.iter().enumerate() {
            let idx = memory_start + i;
            if idx < self.controller.inputs() {
                input[idx] = val;
            }
        }

        input
    }
    /// Execute the NTM using learned rules from topological memory
    pub fn execute_with_stored(&mut self, memory: &TopoLedger<T>) -> crate::Result<()>
    where
        T: NumAssign + core::iter::Sum,
    {
        // Get current head (state and symbol)
        let head = self.head();

        // Try to find a matching rule in the rulespace
        if let Some(rule) = memory.find_rule_by_head(head.view()) {
            // Found a relevant pattern in memory - use the learned rule
            let Tail {
                state: next_state,
                symbol: next_symbol,
                direction,
            } = rule.tail().copied();

            // Update tape
            if self.position >= self.tape.len() {
                self.tape.resize(self.position + 1, 0);
            }
            self.tape[self.position] = next_symbol;

            // Update state
            self.state = next_state;

            // Move head according to direction
            match direction {
                Direction::Left => {
                    if self.position > 0 {
                        self.position -= 1;
                    } else {
                        self.tape.insert(0, 0);
                    }
                }
                Direction::Right => {
                    self.position += 1;
                    if self.position >= self.tape.len() {
                        self.tape.push(0);
                    }
                }
                Direction::Stay => {}
            }

            // Create tail for adapting weights
            let tail = Tail::new(direction, next_state, next_symbol);

            // Update neural weights to reinforce this behavior
            // This uses the learning_rate to gradually adapt the neural model
            self.adapt_to_target(tail)?;

            return Ok(());
        }

        // No rule found in memory, fall back to neural controller
        self.step()
    }

    /// forward input through the controller
    pub fn forward(&self, input: &Array1<T>) -> cnc::Result<Array1<T>> {
        self.controller.forward(input)
    }
    /// train the model to learn the given dataset for a number of epochs
    pub fn learn_sequence<U, V>(
        &mut self,
        inputs: &ArrayBase<U, Ix1>,
        targets: &ArrayBase<V, Ix1>,
    ) -> crate::Result<T>
    where
        U: Data<Elem = usize>,
        V: Data<Elem = usize>,
        T: NumAssign + core::iter::Sum,
        NeuralEngine<T>: ComputationalEngine<usize, [usize; 3], Store = Vec<usize>>,
    {
        if inputs.len() != targets.len() {
            return Err(crate::ActorError::InvalidShape(format!(
                "The input and targets must have the same shape: {:?} != {:?}",
                inputs.len(),
                targets.len()
            )));
        }
        // take a snapshot of the machine so that we can restore it after training
        let snapshot = self.snapshot().cloned();

        // Determine required tape length
        let max_pos = snapshot.position() + inputs.len();
        if self.tape.len() < max_pos {
            self.tape.resize(max_pos, 0);
        }

        let mut total_error = T::zero();

        // Process each input in the sequence
        for (&input_symbol, &expected) in inputs.iter().zip(targets.iter()) {
            // Write input to current position
            if self.position >= self.tape.len() {
                self.tape.push(input_symbol);
            } else {
                self.tape[self.position] = input_symbol;
            }

            // Step the machine
            self.step()?;

            // Calculate error (if output differs from expected)
            if self.tape[self.position] != expected {
                // Create target for training
                let target = Tail::new(
                    self.determine_best_direction(expected),
                    self.state,
                    expected,
                );

                // Adapt weights to the target pattern
                self.adapt_to_target(target)?;

                // Track error
                total_error += T::one();
            }
        }

        // Restore original state
        self.restore_from_snapshot(snapshot);

        Ok(total_error)
    }
    /// train the model to learn the given dataset 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
        U: Data<Elem = usize>,
        V: Data<Elem = usize>,
        T: NumAssign + core::iter::Sum,
    {
        if inputs.len() != targets.len() {
            return Err(crate::ActorError::InvalidShape(
                "Input and output sequences must have the same length".to_string(),
            ));
        }

        let snapshot = self.snapshot().cloned();

        let mut total_error = T::zero();

        // Training loop
        for _ in 0..epochs {
            // restore the original configuration before each epoch
            self.restore_from_snapshot(snapshot.clone());

            total_error += self.learn_sequence(inputs, targets)?;
        }

        Ok(total_error / T::from_usize(epochs).unwrap())
    }
    /// Predict the next n symbols in the sequence
    pub fn predict_sequence(&mut self, n: usize) -> Vec<usize> {
        let snapshot = self.snapshot().cloned();

        let mut predictions = Vec::with_capacity(n);

        // Run the machine forward to generate predictions
        for _ in 0..n {
            if let Ok(()) = self.step() {
                predictions.push(self.tape[snapshot.position()]);
            } else {
                break;
            }
        }

        // Restore original configuration
        self.restore_from_snapshot(snapshot);

        predictions
    }
    /// train the engine on a sequence of inputs with their expected targets
    pub fn learn_sequences_for<U, V>(
        &mut self,
        inputs: &ArrayBase<U, Ix2>,
        targets: &ArrayBase<V, Ix2>,
        epochs: usize,
    ) -> crate::Result<T>
    where
        U: Data<Elem = usize>,
        V: Data<Elem = usize>,
        T: NumAssign + core::iter::Sum,
    {
        if inputs.nrows() != targets.nrows() {
            return Err(crate::ActorError::InvalidShape(format!(
                "the number of input and target rows must be the same for batching: {:?} != {:?}",
                inputs.nrows(),
                targets.nrows()
            )));
        }
        let batch_size = inputs.nrows();
        let mut error = T::zero();
        for _e in 0..epochs {
            for (x, tgt) in inputs.rows().into_iter().zip(targets.rows()) {
                error += self.learn_sequence(&x, &tgt)?;
            }
        }
        Ok(error / T::from(epochs * batch_size).unwrap())
    }
    /// read from memory using attention mechanism
    pub fn read_memory(&self) -> Array1<T>
    where
        for<'a> ndarray::ArrayView2<'a, T>: ndarray::linalg::Dot<Array1<T>, Output = Array1<T>>,
    {
        // Read from memory using attention mechanism
        self.memory().t().dot(&self.read_weights)
    }
    /// Perform a single step of the Turing machine
    pub fn step(&mut self) -> crate::Result<()> {
        // Read current symbol
        let symbol = if self.position < self.tape.len() {
            self.tape[self.position]
        } else {
            0 // Default empty symbol
        };

        // Create controller input from state and symbol
        let controller_input = self.encode_input_symbol(symbol);

        // Process input through controller (neural network)
        let controller_output = self.forward(&controller_input)?;

        // Extract actions from controller output
        let Tail {
            state: next_state,
            symbol: next_symbol,
            direction,
        } = self.decode_outputs_into_tail(controller_output);

        // Update tape
        if self.position >= self.tape.len() {
            self.tape.resize(self.position + 1, 0);
        }
        self.tape[self.position] = next_symbol;

        // Update state
        self.state = next_state;

        // Move head according to direction
        match direction {
            Direction::Left => {
                if self.position > 0 {
                    self.position -= 1;
                } else {
                    self.tape.insert(0, 0);
                }
            }
            Direction::Right => {
                self.position += 1;
                if self.position >= self.tape.len() {
                    self.tape.push(0);
                }
            }
            Direction::Stay => {}
        }

        Ok(())
    }
    /// update the attention mechanism using controller output
    pub fn update_attention(&mut self, inputs: Array1<T>) {
        // Generate key vectors for content-based addressing
        let key = self.controller().attention().dot(&inputs);

        // Calculate content-based attention using cosine similarity
        let d_memory = self.features().codex();
        let mut similarities = Array1::<T>::zeros(d_memory);
        let key_norm = key.dot(&key).sqrt();

        if key_norm > T::zero() {
            // Calculate similarity with each memory row
            for i in 0..d_memory {
                let memory_row = self.memory.row(i).to_owned();
                let mem_norm = memory_row.dot(&memory_row).sqrt();

                if mem_norm > T::zero() {
                    let similarity = memory_row.dot(&key) / (key_norm * mem_norm);
                    similarities[i] = similarity;
                }
            }
        }

        // Apply softmax to get normalized attention weights
        let max_sim = similarities.fold(T::neg_infinity(), |m, &x| if x > m { x } else { m });
        let mut exp_similarities = similarities.mapv(|x| (x - max_sim).exp());
        let sum_exp = exp_similarities.sum();

        if sum_exp > T::zero() {
            exp_similarities.mapv_inplace(|x| x / sum_exp);
        } else {
            // If all similarities are extremely negative, use uniform weights
            exp_similarities.fill(T::one() / T::from(d_memory).unwrap());
        }

        // Split attention for read and write weights (first half for reading, second half for writing)
        let attention_size = inputs.len();
        let read_size = attention_size / 2;

        // Update read weights
        self.read_weights = exp_similarities.clone();

        // Get write gate from second half of input - determines how much to update write weights
        if attention_size > read_size {
            let write_intensity = inputs[read_size];
            let write_gate = T::one() / (T::one() + (-write_intensity).exp()); // sigmoid

            // Blend previous and new write weights
            for i in 0..d_memory {
                self.write_weights[i] = (T::one() - write_gate) * self.write_weights[i]
                    + write_gate * exp_similarities[i];
            }
        }
    }
    /// write to memory using attention mechanism
    pub fn write_memory(&mut self, erase: &Array1<T>, add: &Array1<T>) {
        let dim_memory = self.features().dim_memory();
        // Erase then add pattern with attention mechanism
        for i in 0..dim_memory.0 {
            let w = self.write_weights[i];
            if w > T::zero() {
                for j in 0..dim_memory.1 {
                    self.memory[[i, j]] =
                        self.memory[[i, j]] * (T::one() - w * erase[j]) + w * add[j];
                }
            }
        }
    }
}

impl<T> NeuralEngine<T> {
    pub(crate) fn tail_to_targets(&self, tail: Tail<usize, usize>) -> Array1<T>
    where
        T: Clone + num_traits::One + num_traits::Zero,
    {
        let n_states = NeuralEngine::<T>::STATES;
        // deconstruct the tail into its constituents
        let Tail {
            direction: tgt_direction,
            state: tgt_state,
            symbol: tgt_symbol,
        } = tail;

        // Create target output (what we want the network to produce)
        let mut output = Array1::<T>::zeros(self.features().outputs());
        // Target state (first part of output)
        if *tgt_state < n_states && *tgt_state < output.len() {
            output[*tgt_state] = T::one();
        }

        // Target symbol (middle part)
        let symbol_start = n_states;
        let symbol_idx = self
            .alphabet
            .iter()
            .position(|&s| s == tgt_symbol)
            .unwrap_or(0);
        if symbol_start + symbol_idx < output.len() {
            output[symbol_start + symbol_idx] = T::one();
        }

        // Target direction (last part)
        let dir_start = symbol_start + self.alphabet.len();
        let dir_idx = match tgt_direction {
            Direction::Left => 0,
            Direction::Stay => 1,
            Direction::Right => 2,
        };

        if dir_start + dir_idx < output.len() {
            output[dir_start + dir_idx] = T::one();
        }
        output
    }
}

impl<T> Default for NeuralEngine<T>
where
    T: Clone + Default + FromPrimitive,
{
    fn default() -> Self {
        Self::new([0, 4, 7], State(0))
    }
}

impl<T> RawEngine for NeuralEngine<T>
where
    T: Send + Sync + core::fmt::Debug,
{
    type Store = Vec<usize>;

    seal!();
}

impl<T> Engine for NeuralEngine<T>
where
    T: Clone + Default + Send + Sync + core::fmt::Debug + FromPrimitive,
{
    seal!();
}

impl<T> ComputationalEngine<usize, [usize; 3]> for NeuralEngine<T>
where
    T: Default + Float + FromPrimitive + ScalarOperand + Send + Sync + core::fmt::Debug,
{
    fn new(alphabet: [usize; 3], initial_state: State<usize>) -> Self {
        Self::new(alphabet, initial_state)
    }

    fn alphabet(&self) -> &[usize; 3] {
        &self.alphabet
    }

    fn alphabet_mut(&mut self) -> &mut [usize; 3] {
        &mut self.alphabet
    }

    fn head(&self) -> Head<&usize, &usize> {
        Head::new(self.state.view(), &self.tape[self.position])
    }

    fn head_mut(&mut self) -> Head<&mut usize, &mut usize> {
        Head::new(self.state.view_mut(), &mut self.tape[self.position])
    }

    fn position(&self) -> usize {
        self.position
    }

    fn position_mut(&mut self) -> &mut usize {
        &mut self.position
    }

    fn state(&self) -> State<&usize> {
        self.state.view()
    }

    fn state_mut(&mut self) -> State<&mut usize> {
        self.state.view_mut()
    }

    fn tape(&self) -> &Vec<usize> {
        &self.tape
    }

    fn tape_mut(&mut self) -> &mut Vec<usize> {
        &mut self.tape
    }

    fn step(&mut self) -> crate::Result<()> {
        self.step()
    }

    fn set_alphabet(&mut self, alphabet: [usize; 3]) {
        self.alphabet = alphabet;
    }

    fn set_position(&mut self, position: usize) {
        self.position = position;
    }

    fn set_state(&mut self, state: State<usize>) {
        self.state = state;
    }

    fn set_tape<I>(&mut self, tape: I)
    where
        I: IntoIterator<Item = usize>,
    {
        self.tape = Vec::from_iter(tape);
    }
}
