From 27bb7017373e1ecdf22cea283e713107ae36e8f7 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 23 Jul 2024 14:07:51 -0500 Subject: [PATCH 1/4] update --- Cargo.toml | 2 +- rstm/Cargo.toml | 18 +++ rstm/examples/default.rs | 34 ++++++ rstm/src/error.rs | 26 ++--- rstm/src/lib.rs | 18 ++- rstm/src/macros.rs | 19 +++ rstm/src/programs/instruction.rs | 109 ----------------- rstm/src/programs/program.rs | 95 --------------- rstm/src/rules/instruction.rs | 122 +++++++++++++++++++ rstm/src/{programs => rules}/mod.rs | 1 + rstm/src/rules/program.rs | 121 +++++++++++++++++++ rstm/src/seal.rs | 6 + rstm/src/state/mod.rs | 66 +++++++---- rstm/src/state/state.rs | 137 ++++++++++++++++++---- rstm/src/state/states/binary.rs | 58 +++++---- rstm/src/state/states/halting.rs | 12 ++ rstm/src/state/transition.rs | 102 ---------------- rstm/src/traits/fsm.rs | 5 + rstm/src/traits/mod.rs | 4 +- rstm/src/traits/stateful.rs | 47 ++++++++ rstm/src/traits/symbolic.rs | 47 +++++++- rstm/src/turing/actor.rs | 49 ++++++++ rstm/src/turing/context.rs | 55 +++++++++ rstm/src/turing/machine.rs | 175 ++++++++++++++++------------ rstm/src/turing/mod.rs | 19 +-- rstm/src/turing/utm.rs | 6 - rstm/src/types/head.rs | 76 ++++++++++++ rstm/src/types/mod.rs | 22 ++-- rstm/src/types/parts.rs | 75 ------------ rstm/src/types/scope.rs | 57 +-------- rstm/src/types/symbol.rs | 14 +++ rstm/src/types/tail.rs | 43 +++++++ rstm/src/types/tape.rs | 165 ++++++++++++++++++++------ 33 files changed, 1132 insertions(+), 673 deletions(-) create mode 100644 rstm/examples/default.rs delete mode 100644 rstm/src/programs/instruction.rs delete mode 100644 rstm/src/programs/program.rs create mode 100644 rstm/src/rules/instruction.rs rename rstm/src/{programs => rules}/mod.rs (99%) create mode 100644 rstm/src/rules/program.rs create mode 100644 rstm/src/state/states/halting.rs delete mode 100644 rstm/src/state/transition.rs create mode 100644 rstm/src/traits/stateful.rs create mode 100644 rstm/src/turing/actor.rs delete mode 100644 rstm/src/turing/utm.rs create mode 100644 rstm/src/types/head.rs delete mode 100644 rstm/src/types/parts.rs create mode 100644 rstm/src/types/symbol.rs create mode 100644 rstm/src/types/tail.rs diff --git a/Cargo.toml b/Cargo.toml index 91aebe7..5888613 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ keywords = [ ] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rstm.git" -version = "0.0.0" +version = "0.0.1" [profile.dev] opt-level = 0 diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 7362619..76349f8 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -20,6 +20,7 @@ default = [ full = [ "default", "serde", + "tracing", ] # [FF] Dependencies @@ -31,6 +32,10 @@ serde = [ "dep:serde", ] +tracing = [ + "dep:tracing", +] + # ********* [FF] Environments ********* std = [ "alloc", @@ -44,9 +49,17 @@ crate-type = ["cdylib", "rlib"] doctest = false test = true +[[example]] +name = "default" +required-features = ["tracing"] + [dependencies] thiserror = "1" +[dev-dependencies] +lazy_static = "1" +tracing-subscriber = { features = [], version = "0.3" } + [dependencies.serde] default-features = false features = ["derive"] @@ -58,6 +71,11 @@ default-features = false features = ["derive"] version = "0.26" +[dependencies.tracing] +features = [] +optional = true +version = "0.1" + [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] diff --git a/rstm/examples/default.rs b/rstm/examples/default.rs new file mode 100644 index 0000000..4fe72b2 --- /dev/null +++ b/rstm/examples/default.rs @@ -0,0 +1,34 @@ +/* + Appellation: default + Contrib: FL03 +*/ +extern crate rstm; + +use rstm::rule; +use rstm::state::binary::BinaryStates::*; +use rstm::prelude::{Direction, Fsm, Instruction, State, Tape}; + +use Direction::Right; + +lazy_static::lazy_static! { + static ref RULESET: Vec> = vec![ + rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], + rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], + rule![(State(Invalid), '0') -> Right(State(Valid), '1',)], + rule![(State(Valid), '1') -> Right(State(Invalid), '0',)], + ]; +} + +fn main() -> Result<(), Box> { + tracing_subscriber::fmt().init(); + let tape = Tape::from_str("1011"); + let initial_state = State(Invalid); + + let rules = vec![ + + ]; + + let mut tm = Fsm::new(initial_state, RULESET.clone(), tape); + tm.run(); + Ok(()) +} diff --git a/rstm/src/error.rs b/rstm/src/error.rs index 33696c6..6e1e192 100644 --- a/rstm/src/error.rs +++ b/rstm/src/error.rs @@ -2,50 +2,42 @@ Appellation: error Contrib: FL03 */ -use crate::state::State; #[derive( Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::VariantNames, thiserror::Error, )] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum FsmError { +pub enum FsmError { #[error("[IndexError] Out of Bounds: {0}")] IndexOutOfBounds(String), #[error("[StateError] Invalid State: {0}")] InvalidState(String), - #[error("[StateError] State not found: {current_state:?} with symbol: {read_symbol}")] - StateNotFound { - current_state: State, - read_symbol: char, - }, - + #[error("[StateError] State Not Found: {0}")] + StateNotFound(String), #[error("Transformation error: {0}")] TransformationError(String), #[error("Unknown error: {0}")] Unknown(String), } -impl FsmError { +impl FsmError { pub fn index_out_of_bounds(err: impl ToString) -> Self { FsmError::IndexOutOfBounds(err.to_string()) } - pub fn invalid_state(err: &str) -> Self { + pub fn invalid_state(err: impl ToString) -> Self { FsmError::InvalidState(err.to_string()) } - pub fn state_not_found(state: State, char: char) -> Self { - FsmError::StateNotFound { - current_state: state, - read_symbol: char, - } + pub fn state_not_found(err: impl ToString) -> Self { + FsmError::StateNotFound(err.to_string()) } - pub fn transformation_error(message: &str) -> Self { + pub fn transformation_error(message: impl ToString) -> Self { FsmError::TransformationError(message.to_string()) } - pub fn unknown(message: &str) -> Self { + pub fn unknown(message: impl ToString) -> Self { FsmError::Unknown(message.to_string()) } } diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index eb97912..df1150c 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -4,9 +4,21 @@ */ //! # rstm //! +//!## Turing Machine //! +//! ### Overview +//! +//! A Turing machine is a mathematical model describing the generalization of computation using +//! a set of symbols and a [tape](Tape). Assuming an infinite tape, the machine can read, write, and move linearly +//! across the tape. The machine uses a set of pre-defined rules to determine the next state and symbol. +//! +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; + #[doc(inline)] -pub use self::{error::FsmError, traits::prelude::*, types::prelude::*}; +pub use self::{error::FsmError, state::State, traits::prelude::*, turing::Fsm, types::prelude::*}; #[macro_use] pub(crate) mod macros; @@ -14,7 +26,7 @@ pub(crate) mod macros; pub(crate) mod seal; pub mod error; -pub mod programs; +pub mod rules; pub mod state; pub mod traits; pub mod turing; @@ -22,7 +34,7 @@ pub mod types; pub mod prelude { pub use crate::error::FsmError; - pub use crate::programs::prelude::*; + pub use crate::rules::prelude::*; pub use crate::state::prelude::*; pub use crate::traits::prelude::*; pub use crate::turing::prelude::*; diff --git a/rstm/src/macros.rs b/rstm/src/macros.rs index b332d50..20b768e 100644 --- a/rstm/src/macros.rs +++ b/rstm/src/macros.rs @@ -3,3 +3,22 @@ Contrib: FL03 */ +#[macro_export] +macro_rules! rule { + [($state:expr, $symbol:literal $(,)?) -> $direction:ident($next:expr, $write:literal $(,)?) $(,)?] => { + $crate::rules::Instruction::new() + .state($state) + .symbol($symbol) + .write_symbol($write) + .direction($crate::Direction::$direction) + .next_state($next) + .build() + }; +} + +#[macro_export] +macro_rules! ruleset { + ($($($rule:tt)*);* $(,)?) => { + vec![$(rule!($($rule)*)),*] + }; +} \ No newline at end of file diff --git a/rstm/src/programs/instruction.rs b/rstm/src/programs/instruction.rs deleted file mode 100644 index 7f71439..0000000 --- a/rstm/src/programs/instruction.rs +++ /dev/null @@ -1,109 +0,0 @@ -/* - Appellation: instruction - Contrib: FL03 -*/ -pub use self::builder::InstructionBuilder; - -use crate::prelude::{Direction, Head, State, Tail}; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Instruction { - pub(crate) direction: Direction, - pub(crate) state: State, - pub(crate) symbol: char, - pub(crate) next_state: State, - pub(crate) write_symbol: char, -} - -impl Instruction { - pub fn new() -> InstructionBuilder { - InstructionBuilder::new() - } - - pub fn state(&self) -> &State { - &self.state - } - - pub fn symbol(&self) -> char { - self.symbol - } - - pub fn next_state(&self) -> &State { - &self.next_state - } - - pub fn write_symbol(&self) -> char { - self.write_symbol - } -} - -mod builder { - use super::*; - - pub struct InstructionBuilder { - pub(crate) direction: Direction, - pub(crate) state: Option>, - pub(crate) symbol: Option, - pub(crate) next_state: Option>, - pub(crate) write_symbol: Option, - } - - impl InstructionBuilder { - pub fn new() -> Self { - Self { - direction: Direction::Right, - state: None, - symbol: None, - next_state: None, - write_symbol: None, - } - } - - pub fn direction(self, direction: Direction) -> Self { - Self { direction, ..self } - } - - pub fn left(self) -> Self { - self.direction(Direction::Left) - } - - pub fn state(self, state: State) -> Self { - Self { - state: Some(state), - ..self - } - } - - pub fn symbol(self, symbol: char) -> Self { - Self { - symbol: Some(symbol), - ..self - } - } - - pub fn next_state(self, next_state: State) -> Self { - Self { - next_state: Some(next_state), - ..self - } - } - - pub fn write_symbol(self, write_symbol: char) -> Self { - Self { - write_symbol: Some(write_symbol), - ..self - } - } - - pub fn build(self) -> Instruction { - Instruction { - direction: self.direction, - state: self.state.expect("state is required"), - symbol: self.symbol.expect("symbol is required"), - next_state: self.next_state.expect("next_state is required"), - write_symbol: self.write_symbol.expect("write_symbol is required"), - } - } - } -} diff --git a/rstm/src/programs/program.rs b/rstm/src/programs/program.rs deleted file mode 100644 index faf91b5..0000000 --- a/rstm/src/programs/program.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* - Appellation: program - Contrib: FL03 -*/ -use super::Instruction; -use crate::state::State; - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Program { - pub(crate) initial_state: State, - pub(crate) instructions: Vec>, -} - -impl Program { - pub fn new(initial_state: State) -> Self { - Self { - initial_state, - instructions: Vec::new(), - } - } - - pub fn with_default_state() -> Self - where - Q: Default, - { - Self::new(State::default()) - } - - pub fn as_slice(&self) -> &[Instruction] { - &self.instructions - } - - pub fn as_mut_slice(&mut self) -> &mut [Instruction] { - &mut self.instructions - } - - pub fn initial_state(&self) -> &State { - &self.initial_state - } - - pub fn instructions(&self) -> &[Instruction] { - &self.instructions - } - - pub fn iter(&self) -> core::slice::Iter> { - self.instructions.iter() - } - - pub fn iter_mut(&mut self) -> core::slice::IterMut> { - self.instructions.iter_mut() - } - - pub fn push(&mut self, instruction: Instruction) { - self.instructions.push(instruction); - } -} - -impl Extend> for Program { - fn extend(&mut self, iter: I) - where - I: IntoIterator>, - { - self.instructions.extend(iter); - } -} - -impl IntoIterator for Program { - type Item = Instruction; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.instructions.into_iter() - } -} - -impl core::ops::Index for Program -where - I: core::slice::SliceIndex<[Instruction]>, -{ - type Output = I::Output; - - fn index(&self, index: I) -> &Self::Output { - &self.instructions[index] - } -} - -impl core::ops::IndexMut for Program -where - I: core::slice::SliceIndex<[Instruction]>, -{ - fn index_mut(&mut self, index: I) -> &mut Self::Output { - &mut self.instructions[index] - } -} diff --git a/rstm/src/rules/instruction.rs b/rstm/src/rules/instruction.rs new file mode 100644 index 0000000..b93c56e --- /dev/null +++ b/rstm/src/rules/instruction.rs @@ -0,0 +1,122 @@ +/* + Appellation: instruction + Contrib: FL03 +*/ +pub use self::builder::InstructionBuilder; + +use crate::prelude::{Direction, Head, State, Tail}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Instruction { + pub head: Head, + pub tail: Tail, +} + +impl Instruction { + pub fn new() -> InstructionBuilder { + InstructionBuilder::new() + } + + pub const fn head(&self) -> &Head { + &self.head + } + + pub const fn tail(&self) -> &Tail { + &self.tail + } + + pub fn direction(&self) -> Direction { + self.tail.direction() + } + + pub const fn state(&self) -> &State { + &self.head.state + } + + pub const fn symbol(&self) -> &S { + self.head().symbol() + } + + pub const fn next_state(&self) -> &State { + self.tail().next_state() + } + + pub const fn write_symbol(&self) -> &S { + self.tail().write_symbol() + } +} + +mod builder { + use super::*; + + pub struct InstructionBuilder { + direction: Direction, + state: Option>, + symbol: Option, + next_state: Option>, + write_symbol: Option, + } + + impl InstructionBuilder { + pub fn new() -> Self { + Self { + direction: Direction::Right, + state: None, + symbol: None, + next_state: None, + write_symbol: None, + } + } + + pub fn direction(self, direction: Direction) -> Self { + Self { direction, ..self } + } + + pub fn left(self) -> Self { + self.direction(Direction::Left) + } + + pub fn state(self, state: State) -> Self { + Self { + state: Some(state), + ..self + } + } + + pub fn symbol(self, symbol: S) -> Self { + Self { + symbol: Some(symbol), + ..self + } + } + + pub fn next_state(self, State(state): State) -> Self { + Self { + next_state: Some(State(state)), + ..self + } + } + + pub fn write_symbol(self, write_symbol: S) -> Self { + Self { + write_symbol: Some(write_symbol), + ..self + } + } + + pub fn build(self) -> Instruction { + Instruction { + head: Head { + state: self.state.expect("state is required"), + symbol: self.symbol.expect("symbol is required"), + }, + tail: Tail { + direction: self.direction, + state: self.next_state.expect("next_state is required"), + symbol: self.write_symbol.expect("write_symbol is required"), + }, + } + } + } +} diff --git a/rstm/src/programs/mod.rs b/rstm/src/rules/mod.rs similarity index 99% rename from rstm/src/programs/mod.rs rename to rstm/src/rules/mod.rs index a4c5440..36dbdc4 100644 --- a/rstm/src/programs/mod.rs +++ b/rstm/src/rules/mod.rs @@ -12,3 +12,4 @@ pub(crate) mod prelude { pub use super::instruction::Instruction; pub use super::program::Program; } + diff --git a/rstm/src/rules/program.rs b/rstm/src/rules/program.rs new file mode 100644 index 0000000..a09b997 --- /dev/null +++ b/rstm/src/rules/program.rs @@ -0,0 +1,121 @@ +/* + Appellation: program + Contrib: FL03 +*/ +use super::Instruction; +use crate::{Head, State, Tail}; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::collections::{btree_set as set, BTreeSet as Set}; +#[cfg(feature = "std")] +use std::collections::{hash_set as set, HashSet as Set}; + +type RuleSet = Set>; + + +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Program { + initial_state: State, + instructions: RuleSet, +} + +impl Program { + pub fn new(State(initial_state): State) -> Self { + Self { + initial_state: State(initial_state), + instructions: RuleSet::new(), + } + } + /// + pub fn with_initial_state(self, initial_state: State) -> Self { + Self { + initial_state, + ..self + } + } + + pub fn with_instructions(self, instructions: RuleSet) -> Self { + Self { + instructions, + ..self + } + } + /// Returns an owned reference to the initial state of the program. + pub const fn initial_state(&self) -> &State { + &self.initial_state + } + /// Returns a reference to the instructions. + pub const fn instructions(&self) -> &RuleSet { + &self.instructions + } + /// Returns a mutable reference to the instructions. + pub fn instructions_mut(&mut self) -> &mut RuleSet { + &mut self.instructions + } + /// Returns an iterator over the elements. + pub fn iter(&self) -> set::Iter> { + self.instructions.iter() + } + /// Returns an owned reference to the element(s) specified by the index. + pub fn get(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq { + self.iter().find(|i| i.head() == head).map(|i| i.tail()) + } +} + +#[cfg(feature = "std")] +impl Program { + pub fn from_instructions(instructions: impl IntoIterator>) -> Self + where + Q: Default + Eq + core::hash::Hash, + S: Default + Eq + core::hash::Hash, + { + Self { + initial_state: State::default(), + instructions: RuleSet::from_iter(instructions), + } + } + + +} +#[cfg(all(feature = "alloc", not(feature = "std")))] +impl Program { + pub fn from_instructions(instructions: impl IntoIterator>) -> Self + where + Q: Default + Ord, + S: Default + Ord, + { + Self { + initial_state: State::default(), + instructions: RuleSet::from_iter(instructions), + } + } + + pub fn iter(&self) -> set::Iter> { + self.instructions.iter() + } + + pub fn iter_mut(&mut self) -> set::IterMut> { + self.instructions.iter_mut() + } +} + +#[cfg(feature = "std")] +impl IntoIterator for Program { + type Item = Instruction; + type IntoIter = set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.instructions.into_iter() + } +} + +#[cfg(all(feature = "alloc", not(feature = "std")))] +impl IntoIterator for Program { + type Item = Instruction; + type IntoIter = set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.instructions.into_iter() + } +} diff --git a/rstm/src/seal.rs b/rstm/src/seal.rs index 6ffe546..cfd0159 100644 --- a/rstm/src/seal.rs +++ b/rstm/src/seal.rs @@ -2,13 +2,19 @@ Appellation: seal Contrib: FL03 */ +#![allow(unused)] //! The public parts of this private module are used to create traits //! that cannot be implemented outside of our own crate. This way we //! can feel free to extend those traits without worrying about it //! being a breaking change for other implementations. +//! + +#[doc(hidden)] +pub(crate) trait Private {} /// If this type is pub but not publicly reachable, third parties /// can't name it and can't implement traits using it. +#[doc(hidden)] pub struct Seal; macro_rules! private { diff --git a/rstm/src/state/mod.rs b/rstm/src/state/mod.rs index aefed7f..047c285 100644 --- a/rstm/src/state/mod.rs +++ b/rstm/src/state/mod.rs @@ -2,41 +2,59 @@ Appellation: state Contrib: FL03 */ -pub use self::{state::State, transition::Transition}; +#[doc(inline)] +pub use self::{state::State, states::*}; pub(crate) mod state; -pub(crate) mod transition; + +pub(crate) mod states { + #[doc(inline)] + pub use self::binary::BinaryState; + + pub mod binary; + pub mod halting; + + pub(crate) mod prelude { + pub use super::binary::*; + } +} pub(crate) mod prelude { - pub use crate::state::{State, Transition}; + + pub use super::state::State; + pub use super::states::prelude::*; +} + +/// +pub trait Mode { +} + +pub trait Haltable { + fn halt(&self) -> bool; } -#[allow(unused)] -#[doc(hidden)] -mod private { - pub trait State { - type Data; +impl Haltable for bool { + fn halt(&self) -> bool { + *self } +} - /// [Stateful] is used to describe objects which rely upon a state. - /// - pub trait Stateful { - type State: State; +impl Haltable for char { + fn halt(&self) -> bool { + *self == 'H' } +} - pub enum TimePerspective { - Past(T), - Present(T), - Future(T), +impl Haltable for String { + fn halt(&self) -> bool { + self.as_str().halt() } +} - pub enum StateGroup - where - S: State, - { - A { prev: S, curr: S }, - B { curr: S, next: S }, - C { prev: S, next: S }, - D { prev: S, curr: S, next: S }, +impl Haltable for &str { + fn halt(&self) -> bool { + let s = self.to_string().to_lowercase(); + matches!(s.as_str(), "h" | "H" | "stop" | "terminate") } } + diff --git a/rstm/src/state/state.rs b/rstm/src/state/state.rs index 25c4394..74f52ba 100644 --- a/rstm/src/state/state.rs +++ b/rstm/src/state/state.rs @@ -3,82 +3,173 @@ Contrib: FL03 */ + #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[repr(transparent)] -pub struct State(pub(crate) T); +pub struct State(pub Q); -impl State { - pub fn new(state: T) -> Self { +impl State { + pub fn new(state: Q) -> Self { Self(state) } - pub fn into_inner(self) -> T { + pub fn into_inner(self) -> Q { self.0 } - pub fn as_ref(&self) -> &T { + pub fn as_ref(&self) -> &Q { &self.0 } - pub fn as_mut(&mut self) -> &mut T { + pub fn as_mut(&mut self) -> &mut Q { &mut self.0 } } -impl AsRef for State { - fn as_ref(&self) -> &T { +impl State { + pub fn is_halt(&self) -> bool { + self.0 == 'H' || self.0 == 'h' + } +} + +impl State<&str> { + pub fn is_halt(&self) -> bool { + self.0.to_lowercase() == "halt" + } +} + +impl State { + pub fn is_halt(&self) -> bool { + self.0.to_lowercase() == "halt" + } +} + +impl AsRef for State { + fn as_ref(&self) -> &Q { &self.0 } } -impl AsMut for State { - fn as_mut(&mut self) -> &mut T { +impl AsMut for State { + fn as_mut(&mut self) -> &mut Q { &mut self.0 } } -impl core::borrow::Borrow for State { - fn borrow(&self) -> &T { +impl core::borrow::Borrow for State { + fn borrow(&self) -> &Q { &self.0 } } -impl core::borrow::BorrowMut for State { - fn borrow_mut(&mut self) -> &mut T { +impl core::borrow::BorrowMut for State { + fn borrow_mut(&mut self) -> &mut Q { &mut self.0 } } -impl core::ops::Deref for State { - type Target = T; +impl core::ops::Deref for State { + type Target = Q; fn deref(&self) -> &Self::Target { &self.0 } } -impl core::ops::DerefMut for State { +impl core::ops::DerefMut for State { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl core::fmt::Display for State +impl core::fmt::Binary for State +where + Q: core::fmt::Binary, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:b}", self.0) + } +} + +impl core::fmt::Display for State where - T: core::fmt::Display, + Q: core::fmt::Display, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", self.0) } } -unsafe impl Send for State where T: Send {} +impl core::fmt::LowerExp for State +where + Q: core::fmt::LowerExp, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:e}", self.0) + } +} + +impl core::fmt::LowerHex for State +where + Q: core::fmt::LowerHex, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:x}", self.0) + } +} + +impl core::fmt::Octal for State +where + Q: core::fmt::Octal, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:o}", self.0) + } +} + +impl core::fmt::UpperExp for State +where + Q: core::fmt::UpperExp, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:E}", self.0) + } +} + +impl core::fmt::UpperHex for State +where + Q: core::fmt::UpperHex, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:X}", self.0) + } +} + +unsafe impl core::marker::Send for State where Q: core::marker::Send {} + +unsafe impl core::marker::Sync for State where Q: core::marker::Sync {} + +impl core::cmp::PartialEq for State +where + Q: core::cmp::PartialEq, +{ + fn eq(&self, other: &Q) -> bool { + self.0 == *other + } +} -unsafe impl Sync for State where T: Sync {} +impl core::cmp::PartialOrd for State +where + Q: core::cmp::PartialOrd, +{ + fn partial_cmp(&self, other: &Q) -> Option { + self.0.partial_cmp(other) + } +} -impl From for State { - fn from(state: T) -> Self { +impl From for State { + fn from(state: Q) -> Self { Self(state) } } diff --git a/rstm/src/state/states/binary.rs b/rstm/src/state/states/binary.rs index 21a14b5..280cc42 100644 --- a/rstm/src/state/states/binary.rs +++ b/rstm/src/state/states/binary.rs @@ -2,6 +2,7 @@ Appellation: state Contrib: FL03 */ +use crate::State; #[derive( Clone, @@ -30,6 +31,7 @@ #[strum_discriminants( name(BinaryStates), derive( + Hash, Ord, PartialOrd, strum::AsRefStr, @@ -41,31 +43,27 @@ strum::VariantNames ) )] -pub enum BinaryState { - Invalid(Q), - Valid(Q), +pub enum BinaryState { + Invalid(State), + Valid(State), } -impl BinaryState { - pub fn invalid(state: Q) -> Self { - Self::Invalid(state) +impl BinaryState { + pub fn invalid(State(state): State) -> Self { + Self::Invalid(State(state)) } - pub fn valid(state: Q) -> Self { - Self::Valid(state) + pub fn valid(State(state): State) -> Self { + Self::Valid(State(state)) } - pub fn into_inner(self) -> Q { + pub fn invalidate(self, state: Q) -> BinaryState { match self { - Self::Invalid(q) => q, - Self::Valid(q) => q, + Self::Invalid(_) => BinaryState::Invalid(State(state)), + Self::Valid(_) => BinaryState::Invalid(State(state)), } } - pub fn invalidate(self) -> Self { - Self::Invalid(self.into_inner()) - } - pub fn kind(&self) -> BinaryStates { match self { Self::Invalid(_) => BinaryStates::Invalid, @@ -73,12 +71,22 @@ impl BinaryState { } } + +} + +impl BinaryState { + pub fn into_inner(self) -> State { + match self { + Self::Invalid(q) => q, + Self::Valid(q) => q, + } + } + pub fn state(&self) -> (BinaryStates, &Q) { (self.kind(), self.as_ref()) } } - -impl AsRef for BinaryState { +impl AsRef for BinaryState { fn as_ref(&self) -> &Q { match self { Self::Invalid(q) => q, @@ -87,7 +95,7 @@ impl AsRef for BinaryState { } } -impl AsMut for BinaryState { +impl AsMut for BinaryState { fn as_mut(&mut self) -> &mut Q { match self { Self::Invalid(q) => q, @@ -96,25 +104,25 @@ impl AsMut for BinaryState { } } -impl core::borrow::Borrow for BinaryState { +impl core::borrow::Borrow for BinaryState { fn borrow(&self) -> &Q { self.as_ref() } } -impl core::borrow::BorrowMut for BinaryState { +impl core::borrow::BorrowMut for BinaryState { fn borrow_mut(&mut self) -> &mut Q { self.as_mut() } } -impl Default for BinaryState { +impl Default for BinaryState { fn default() -> Self { - Self::Invalid(Q::default()) + Self::invalid(State::default()) } } -impl core::ops::Deref for BinaryState { +impl core::ops::Deref for BinaryState { type Target = Q; fn deref(&self) -> &Self::Target { @@ -122,13 +130,13 @@ impl core::ops::Deref for BinaryState { } } -impl core::ops::DerefMut for BinaryState { +impl core::ops::DerefMut for BinaryState { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } } -impl core::fmt::Display for BinaryState +impl core::fmt::Display for BinaryState where Q: core::fmt::Display, { diff --git a/rstm/src/state/states/halting.rs b/rstm/src/state/states/halting.rs new file mode 100644 index 0000000..8e4f081 --- /dev/null +++ b/rstm/src/state/states/halting.rs @@ -0,0 +1,12 @@ +/* + Appellation: halting + Contrib: FL03 +*/ + +pub trait PowerMode { + private!(); +} + +pub enum On { + +} \ No newline at end of file diff --git a/rstm/src/state/transition.rs b/rstm/src/state/transition.rs deleted file mode 100644 index ee76e44..0000000 --- a/rstm/src/state/transition.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - Appellation: transition - Contrib: FL03 -*/ -pub use self::builder::TransitionBuilder; -use crate::prelude::{Direction, State}; - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Transition { - pub(crate) current_state: State, - pub(crate) read_symbol: char, - pub(crate) next_state: State, - pub(crate) write_symbol: char, - pub(crate) direction: Direction, -} - -impl Transition { - pub fn new(initial_state: State) -> TransitionBuilder - where - T: Default, - { - TransitionBuilder::new(initial_state) - } - - pub const fn current_state(&self) -> &State { - &self.current_state - } - - pub fn read_symbol(&self) -> char { - self.read_symbol - } - - pub const fn next_state(&self) -> &State { - &self.next_state - } - - pub fn write_symbol(&self) -> char { - self.write_symbol - } - - pub fn direction(&self) -> Direction { - self.direction - } -} - -mod builder { - use super::*; - - pub struct TransitionBuilder { - current_state: State, - read_symbol: char, - next_state: State, - write_symbol: char, - direction: Direction, - } - - impl TransitionBuilder { - pub fn new(initial_state: State) -> Self - where - T: Default, - { - Self { - current_state: initial_state, - read_symbol: '\0', - next_state: State::default(), - write_symbol: '\0', - direction: Direction::Right, - } - } - - pub fn read_symbol(mut self, read_symbol: char) -> Self { - self.read_symbol = read_symbol; - self - } - - pub fn next_state(mut self, next_state: State) -> Self { - self.next_state = next_state; - self - } - - pub fn write_symbol(mut self, write_symbol: char) -> Self { - self.write_symbol = write_symbol; - self - } - - pub fn direction(mut self, direction: Direction) -> Self { - self.direction = direction; - self - } - - pub fn build(self) -> Transition { - Transition { - current_state: self.current_state, - read_symbol: self.read_symbol, - next_state: self.next_state, - write_symbol: self.write_symbol, - direction: self.direction, - } - } - } -} diff --git a/rstm/src/traits/fsm.rs b/rstm/src/traits/fsm.rs index c181e07..ef96a06 100644 --- a/rstm/src/traits/fsm.rs +++ b/rstm/src/traits/fsm.rs @@ -2,3 +2,8 @@ Appellation: fsm Contrib: FL03 */ + +// pub trait Rule { +// type +// type State; +// } diff --git a/rstm/src/traits/mod.rs b/rstm/src/traits/mod.rs index f451bae..0ad9e1a 100644 --- a/rstm/src/traits/mod.rs +++ b/rstm/src/traits/mod.rs @@ -7,8 +7,10 @@ pub use self::symbolic::Symbolic; #[doc(hidden)] pub mod fsm; +#[doc(hidden)] +pub mod stateful; pub mod symbolic; pub(crate) mod prelude { pub use super::symbolic::*; -} \ No newline at end of file +} diff --git a/rstm/src/traits/stateful.rs b/rstm/src/traits/stateful.rs new file mode 100644 index 0000000..c5d16c0 --- /dev/null +++ b/rstm/src/traits/stateful.rs @@ -0,0 +1,47 @@ +/* + Appellation: stateful + Contrib: FL03 +*/ + + +/// S +pub trait BaseState { + type Data; + + fn data(&self) -> &Self::Data; + + fn data_mut(&mut self) -> &mut Self::Data; + + fn set_data(&mut self, data: Self::Data); + + +} + + +/// [Stateful] is used to describe objects which rely upon a state. +/// +pub trait Stateful { + type State: BaseState; +} + +#[allow(unused)] +#[doc(hidden)] +mod private { + use super::BaseState; + + pub enum TimePerspective { + Past(T), + Present(T), + Future(T), + } + + pub enum StateGroup + where + S: BaseState, + { + A { prev: S, curr: S }, + B { curr: S, next: S }, + C { prev: S, next: S }, + D { prev: S, curr: S, next: S }, + } +} diff --git a/rstm/src/traits/symbolic.rs b/rstm/src/traits/symbolic.rs index 14fe283..b9910e8 100644 --- a/rstm/src/traits/symbolic.rs +++ b/rstm/src/traits/symbolic.rs @@ -3,10 +3,51 @@ Contrib: FL03 */ -pub trait Symbolic { +pub trait Alphabet { + type Elem; + + fn symbols(&self) -> Vec; +} + +pub trait AsRefChar { + fn as_char(&self) -> &char; +} + + +pub trait Symbol { + fn as_ptr(&self) -> *const char; + fn symbol(&self) -> char; } -pub trait Alphabet { - fn symbols(&self) -> Vec; +pub trait Symbolic: Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash {} + +/* + ************* Implementations ************* +*/ + +impl AsRefChar for T where T: AsRef { + fn as_char(&self) -> &char { + self.as_ref() + } +} + +impl Alphabet for Vec { + type Elem = char; + + fn symbols(&self) -> Vec { + self.clone() + } } + +impl Symbol for char { + fn as_ptr(&self) -> *const char { + self as *const char + } + + fn symbol(&self) -> char { + *self + } +} + +impl Symbolic for S where S: Symbol + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash {} \ No newline at end of file diff --git a/rstm/src/turing/actor.rs b/rstm/src/turing/actor.rs new file mode 100644 index 0000000..ba35c70 --- /dev/null +++ b/rstm/src/turing/actor.rs @@ -0,0 +1,49 @@ +/* + Appellation: actor + Contrib: FL03 +*/ +use crate::prelude::{Direction, Head, Tail}; +use crate::state::State; + +pub struct Actor { + pub(crate) head: Head, + pub(crate) tail: Tail, +} + +impl Actor { + pub fn new(head: Head, tail: Tail) -> Self { + Self { head, tail } + } + + pub const fn head(&self) -> &Head { + &self.head + } + + pub const fn tail(&self) -> &Tail { + &self.tail + } + + pub fn head_mut(&mut self) -> &mut Head { + &mut self.head + } + /// Returns a mutable reference to the tail of the agent + pub fn tail_mut(&mut self) -> &mut Tail { + &mut self.tail + } + /// Returns the current [state](State) the agent is in + pub fn current_state(&self) -> &State { + self.head.state() + } + /// Returns a copy of the [direction](Direction) the agent is instructed to move + pub fn direction(&self) -> Direction { + self.tail().direction() + } + /// Returns an immutable, owned reference to the next [state](State) + pub fn next_state(&self) -> &State { + self.tail().next_state() + } + /// Returns a copy of the symbol the agent is instructed to write + pub fn write_symbol(&self) -> char { + self.tail().symbol + } +} diff --git a/rstm/src/turing/context.rs b/rstm/src/turing/context.rs index 8b13789..6c4ce9c 100644 --- a/rstm/src/turing/context.rs +++ b/rstm/src/turing/context.rs @@ -1 +1,56 @@ +/* + Appellation: context + Contrib: FL03 +*/ +use crate::rules::Program; +use crate::state::State; +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Context { + pub(crate) program: Program, + pub(crate) state: Option>, +} + +impl Context { + pub fn new(program: Program, state: State) -> Self { + Self { + program, + state: Some(state), + } + } + /// + pub fn from_program(program: Program) -> Self { + Self { program, state: None } + } + + pub fn from_state(state: State) -> Self where Q: Default, S: Default { + Self { + program: Program::default(), + state: Some(state), + } + } + + + /// Returns the current state of the system; + /// if the state is [none](Option::None), assumes the initial state. + pub fn current_state(&self) -> &State { + self.state.as_ref().unwrap_or(self.initial_state()) + } + + pub const fn initial_state(&self) -> &State { + &self.program.initial_state() + } + + pub fn program(&self) -> &Program { + &self.program + } + + pub fn program_mut(&mut self) -> &mut Program { + &mut self.program + } + + pub fn set_state(&mut self, state: State) { + self.state = Some(state); + } +} diff --git a/rstm/src/turing/machine.rs b/rstm/src/turing/machine.rs index c9f512b..16271d4 100644 --- a/rstm/src/turing/machine.rs +++ b/rstm/src/turing/machine.rs @@ -2,109 +2,134 @@ Appellation: tm Contrib: FL03 */ -use super::Registry; -use crate::prelude::{FsmError, Tape}; -use crate::state::{State, Transition}; +use super::Context; -pub struct Context { - pub(crate) initial_state: State, - pub(crate) states: Vec>, - pub(crate) transitions: Vec>, +use crate::prelude::{FsmError, Head, Registry, Tape}; +use crate::rules::Instruction; +use crate::state::{Haltable, State}; +use crate::Symbolic; + +/// # Finite State Machine +/// + +#[derive(Clone, Debug,)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Fsm { + pub(crate) ctx: Context, + pub(crate) registry: Registry, + pub(crate) tape: Tape, } -impl Context { - pub fn new(initial_state: State) -> Self { - Self { - initial_state, - states: Vec::new(), - transitions: Vec::new(), - } +impl Fsm { + pub const fn context(&self) -> &Context { + &self.ctx } - pub fn with_states(self, states: Vec>) -> Self { - Self { states, ..self } + pub fn current_state(&self) -> &State { + self.context().current_state() } - pub fn with_transitions(self, transitions: Vec>) -> Self { - Self { - transitions, - ..self - } + pub fn head(&self) -> Head where Q: Clone, S: Clone { + let state = self.current_state().clone(); + let symbol = self.tape.read().unwrap().clone(); + Head::new(state, symbol) + } + /// + pub const fn registry(&self) -> &Registry { + &self.registry } - pub fn initial_state(&self) -> &State { - &self.initial_state + pub fn registry_mut(&mut self) -> &mut Registry { + &mut self.registry } - pub fn states(&self) -> &Vec> { - &self.states + pub const fn tape(&self) -> &Tape { + &self.tape } - pub fn transitions(&self) -> &Vec> { - &self.transitions + pub fn tape_mut(&mut self) -> &mut Tape { + &mut self.tape } } -/// -pub struct TuringMachine { - pub(crate) ctx: Context, - pub(crate) cstate: State, - pub(crate) registry: Registry, - pub(crate) tape: Tape, -} -impl TuringMachine { - pub fn new(initial_state: State, tape: Tape, transforms: Vec) -> Self { - let ctx = Context::new(initial_state.clone()); - let mut transitions = Registry::new(); - for trs in transforms { - transitions.insert( - (trs.current_state.clone(), trs.read_symbol), - (trs.next_state, trs.write_symbol, trs.direction), - ); +#[cfg(feature = "std")] +impl Fsm +where + Q: Eq + core::hash::Hash, + S: Symbolic +{ + pub fn new( + initial_state: State, + instructions: impl IntoIterator>, + tape: Tape, + + ) -> Self where Q: Clone + Default, S: Clone + Default { + let ctx = Context::from_state(initial_state.clone()); + let mut registry = Registry::new(); + for t in instructions { + registry.insert(t.head, t.tail); } - TuringMachine { - cstate: initial_state, + Fsm { ctx, tape, - registry: transitions, + registry, } } - - pub const fn context(&self) -> &Context { - &self.ctx - } - - pub const fn current_state(&self) -> &State { - &self.cstate - } - - pub const fn tape(&self) -> &Tape { - &self.tape - } - - pub fn step(&mut self) -> Result<(), FsmError> { - let cursor = self.cstate.clone(); - let current_symbol = *self.tape.read()?; - if let Some(&(ref next_state, write_symbol, direction)) = - self.registry.get(&(cursor.clone(), current_symbol)) - { - self.tape.write(write_symbol); - self.tape.step(direction); - self.cstate = next_state.clone(); + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all, name = "step", target = "fsm"))] + pub fn step(&mut self) -> Result<(), FsmError> where Q: Clone, S: Clone { + #[cfg(feature = "tracing")] + tracing::info!("Stepping..."); + let registry = self.registry.clone(); + // Get a clone of the current state + let cst = self.current_state().clone(); + let sym = self.tape().read()?.clone(); + let head = Head::new(cst.clone(), sym); + if let Some(tail) = registry.get(&head).cloned() { + let nxt = self.tape.update(tail); + self.ctx.set_state(nxt); return Ok(()); } - Err(FsmError::state_not_found(cursor, current_symbol)) + Err(FsmError::state_not_found("")) } - - pub fn run(&mut self) { + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all, name = "run", target = "fsm"))] + pub fn run(mut self) -> Result<(), FsmError> where Q: Clone, S: Clone { + #[cfg(feature = "tracing")] + tracing::info!("Running the program..."); loop { - self.tape.print_tape(); - self.step().expect("Error stepping through machine"); - if *self.cstate == "HALT" { - break; + #[cfg(feature = "tracing")] + tracing::info!("{}", &self.tape); + match self.step() { + Ok(_) => continue, + Err(e) => { + return Err(e); + } } } } } + +impl Fsm +where + Q: Clone + Eq + core::hash::Hash + Haltable, +{ + pub fn run_haltable(&mut self) -> Result<(), FsmError> { + let _ = loop { + dbg!(self.tape()); + match self.step() { + Ok(_) => (), + Err(e) => { + eprintln!("{}", e); + break; + } + } + + if self.current_state().halt() { + break; + } + }; + + Ok(()) + } +} diff --git a/rstm/src/turing/mod.rs b/rstm/src/turing/mod.rs index 49569f7..65a9106 100644 --- a/rstm/src/turing/mod.rs +++ b/rstm/src/turing/mod.rs @@ -2,23 +2,16 @@ Appellation: turing Contrib: FL03 */ -pub use self::machine::TuringMachine; +#[doc(inline)] +pub use self::{actor::Actor, context::Context, machine::Fsm}; +pub(crate) mod actor; +pub(crate) mod context; pub(crate) mod machine; -#[doc(hidden)] -pub mod context; -#[doc(hidden)] -pub mod utm; - pub(crate) mod prelude { - pub use super::machine::TuringMachine; + pub use super::machine::Fsm; } -use crate::prelude::{Direction, State}; -use std::collections::HashMap; -/// -pub(crate) type Registry = HashMap<(State, char), (State, char, Direction)>; - +#[doc(hidden)] pub trait Turing {} - diff --git a/rstm/src/turing/utm.rs b/rstm/src/turing/utm.rs deleted file mode 100644 index 9082e93..0000000 --- a/rstm/src/turing/utm.rs +++ /dev/null @@ -1,6 +0,0 @@ -/* - Appellation: utm - Contrib: FL03 -*/ - -pub trait UTM {} diff --git a/rstm/src/types/head.rs b/rstm/src/types/head.rs new file mode 100644 index 0000000..cfb2c3b --- /dev/null +++ b/rstm/src/types/head.rs @@ -0,0 +1,76 @@ +/* + Appellation: head + Contrib: FL03 +*/ +use crate::state::State; + +/// The head of a turing machine generally speaks to the current state and symbol of the machine +/// w.r.t. the [tape](crate::types::Tape). Currently, the head simply stores a reference to the +/// +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Head { + pub state: State, + pub symbol: S, + // pub(crate) _ptr: , +} + +impl Head { + pub fn new(State(state): State, symbol: S) -> Self { + Self { + state: State(state), + symbol, + } + } + /// Returns a reference to the current [state](State) and symbol returing a 2-tuple + pub fn as_tuple(&self) -> (&State, &S) { + (&self.state, &self.symbol) + } + /// Consumes the head and returns the current [state](State) and symbol as a 2-tuple + pub fn into_tuple(self) -> (State, S) { + (self.state, self.symbol) + } + /// Returns a mutable reference to the current [state](State) and symbol as a 2-tuple + pub fn as_mut_tuple(&mut self) -> (&mut State, &mut S) { + (&mut self.state, &mut self.symbol) + } + /// Updates the current [state](State) + pub fn set_state(&mut self, state: State) { + self.state = state; + } + /// Updates the current symbol + pub fn set_symbol(&mut self, symbol: S) { + self.symbol = symbol; + } + /// Returns a reference to the current [state](State) + pub const fn state(&self) -> &State { + &self.state + } + /// Returns a mutable reference to the current [state](State) + pub fn state_mut(&mut self) -> &mut State { + &mut self.state + } + /// Returns a reference to the current symbol + pub const fn symbol(&self) -> &S { + &self.symbol + } + /// Returns a mutable reference to the current symbol + pub fn symbol_mut(&mut self) -> &mut S { + &mut self.symbol + } + /// Updates the current [state](State) and symbol + pub fn update(&mut self, state: Option>, symbol: Option) { + if let Some(state) = state { + self.state = state; + } + if let Some(symbol) = symbol { + self.symbol = symbol; + } + } +} + +impl From<(State, S)> for Head { + fn from((state, symbol): (State, S)) -> Self { + Self::new(state, symbol) + } +} diff --git a/rstm/src/types/mod.rs b/rstm/src/types/mod.rs index 08c6b28..4029150 100644 --- a/rstm/src/types/mod.rs +++ b/rstm/src/types/mod.rs @@ -3,24 +3,24 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{ - direction::Direction, - parts::{Head, Tail}, - scope::Scope, - tape::Tape, -}; +pub use self::{direction::Direction, head::Head, tail::Tail, tape::Tape}; pub mod direction; -pub mod parts; +pub mod head; +#[doc(hidden)] pub mod scope; +#[doc(hidden)] +pub mod symbol; +pub mod tail; pub mod tape; pub(crate) mod prelude { pub use super::direction::Direction; - pub use super::parts::{Head, Tail}; - pub use super::scope::Scope; + pub use super::head::Head; + pub use super::tail::Tail; pub use super::tape::Tape; + pub use super::Registry; } -#[allow(unused)] -pub(crate) type HeadMap = std::collections::HashMap, Tail>; +/// A registry of [head](Head) and [tail](Tail) pairs +pub type Registry = std::collections::HashMap, Tail>; diff --git a/rstm/src/types/parts.rs b/rstm/src/types/parts.rs deleted file mode 100644 index 1fe3126..0000000 --- a/rstm/src/types/parts.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - Appellation: head - Contrib: FL03 -*/ -use crate::prelude::{Direction, State}; - -/// The head of a turing machine generally speaks to the current state and symbol of the machine -/// w.r.t. the [tape](crate::types::Tape). Currently, the head simply stores a reference to the -/// -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Head { - pub(crate) position: usize, - pub(crate) state: State, - // pub(crate) _ptr: , -} - -impl Head { - pub fn new(position: usize, state: State) -> Self { - Self { position, state } - } - - pub fn move_head(&mut self, direction: Direction) { - self.position = direction.apply(self.position); - } - - pub fn step(self, direction: Direction) -> Self { - Self { - position: direction.apply(self.position), - ..self - } - } - - pub fn position(&self) -> usize { - self.position - } - - pub const fn state(&self) -> &State { - &self.state - } - - pub fn state_mut(&mut self) -> &mut State { - &mut self.state - } -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Tail { - pub(crate) next_state: State, - pub(crate) write_symbol: char, - pub(crate) direction: Direction, -} - -impl Tail { - pub fn new(next_state: State, write_symbol: char, direction: Direction) -> Self { - Self { - next_state, - write_symbol, - direction, - } - } - - pub fn next_state(&self) -> &State { - &self.next_state - } - - pub fn write_symbol(&self) -> char { - self.write_symbol - } - - pub fn direction(&self) -> Direction { - self.direction - } -} diff --git a/rstm/src/types/scope.rs b/rstm/src/types/scope.rs index ebae99e..b245e3f 100644 --- a/rstm/src/types/scope.rs +++ b/rstm/src/types/scope.rs @@ -2,59 +2,10 @@ Appellation: agent Contrib: FL03 */ -use super::{Head, Tail}; -use crate::prelude::{Direction, State}; -pub struct Scope { - pub(crate) head: Head, - pub(crate) tail: Tail, -} - -impl Scope { - pub fn new(head: Head, tail: Tail) -> Self { - Self { head, tail } - } - - pub const fn head(&self) -> &Head { - &self.head - } - - pub const fn tail(&self) -> &Tail { - &self.tail - } - - pub fn head_mut(&mut self) -> &mut Head { - &mut self.head - } - /// Returns a mutable reference to the tail of the agent - pub fn tail_mut(&mut self) -> &mut Tail { - &mut self.tail - } - /// Mutably shift the agent in the specified [direction](Direction) - pub fn move_head(&mut self, direction: Direction) { - self.head.move_head(direction); - } - /// Returns the current [state](State) the agent is in - pub fn current_state(&self) -> &State { - self.head.state() - } - /// Returns a copy of the [direction](Direction) the agent is instructed to move - pub fn direction(&self) -> Direction { - self.tail().direction() - } - /// Returns an immutable, owned reference to the next [state](State) - pub fn next_state(&self) -> &State { - self.tail().next_state() - } - /// Returns a copy of the symbol the agent is instructed to write - pub fn write_symbol(&self) -> char { - self.tail().write_symbol - } +use crate::state::State; - pub fn step(self) -> Self { - Self { - head: self.head.step(self.tail.direction), - ..self - } - } +pub struct Observer { + pub position: usize, + pub state: State, } diff --git a/rstm/src/types/symbol.rs b/rstm/src/types/symbol.rs new file mode 100644 index 0000000..cecf9c4 --- /dev/null +++ b/rstm/src/types/symbol.rs @@ -0,0 +1,14 @@ +/* + Appellation: symbol + Contrib: FL03 +*/ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[repr(transparent)] +pub struct Symbol(pub S); + + +pub struct Alphabet { + pub symbols: Vec>, +} diff --git a/rstm/src/types/tail.rs b/rstm/src/types/tail.rs new file mode 100644 index 0000000..ad23884 --- /dev/null +++ b/rstm/src/types/tail.rs @@ -0,0 +1,43 @@ +/* + Appellation: head + Contrib: FL03 +*/ +use crate::{Direction, State}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Tail { + pub(crate) direction: Direction, + pub(crate) state: State, + pub(crate) symbol: S, +} + +impl Tail { + pub fn new(direction: Direction, State(state): State, symbol: S) -> Self { + Self { + direction, + state: State(state), + symbol, + } + } + /// Returns the direction, state, and symbol as a 3-tuple + pub fn as_tuple(&self) -> (Direction, &State, &S) { + (self.direction, &self.state, &self.symbol) + } + /// Consumes the tail and returns the direction, state, and symbol as a 3-tuple + pub fn into_tuple(self) -> (Direction, State, S) { + (self.direction, self.state, self.symbol) + } + /// Returns the direction the [head](crate::Head) is instructed to move + pub fn direction(&self) -> Direction { + self.direction + } + /// Returns the next [state](State) the agent is instructed to move to + pub const fn next_state(&self) -> &State { + &self.state + } + /// Returns the [symbol](crate::Symbolic) the [head](crate::Head) is instructed to write + pub const fn write_symbol(&self) -> &S { + &self.symbol + } +} diff --git a/rstm/src/types/tape.rs b/rstm/src/types/tape.rs index dd805a3..e1bec9f 100644 --- a/rstm/src/types/tape.rs +++ b/rstm/src/types/tape.rs @@ -2,14 +2,23 @@ Appellation: tape Contrib: FL03 */ -use crate::{Direction, FsmError}; +use crate::{Direction, FsmError, State, Tail}; +use core::cell::Cell; -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[allow(unused)] +#[doc(hidden)] +pub struct Slider { + + scope: usize, + state: *const State, +} + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Tape { pos: usize, store: Vec, - ticks: usize, + ticks: Cell, } impl Tape { @@ -17,7 +26,7 @@ impl Tape { Tape { pos: 0, store: Vec::::new(), - ticks: 0, + ticks: Cell::default(), } } /// Returns an owned reference to the store as a [slice](core::slice) @@ -28,6 +37,10 @@ impl Tape { pub fn as_mut_slice(&mut self) -> &mut [S] { &mut self.store } + /// Returns the number of elements in the tape. + pub fn len(&self) -> usize { + self.store.len() + } /// Given an index, return a reference to the symbol at that index; /// panics if the index is out of bounds. pub fn get(&self, idx: I) -> Option<&I::Output> @@ -36,10 +49,37 @@ impl Tape { { self.store.get(idx) } + + pub fn to_string(&self) -> String + where + S: alloc::string::ToString, + { + format!( + "{}", + self.store + .iter() + .enumerate() + .map(|(i, c)| { + match i { + c if i == self.pos => format!("[{}]", &c), + _ => c.to_string(), + } + }) + .collect::() + ) + } + /// Removes and returns the last element of the tape, or `None` if it is empty. + pub fn pop(&mut self) -> Option { + self.store.pop() + } /// Returns the current position of the tape head; pub fn position(&self) -> usize { self.pos } + /// Appends the given element to the back of the collection. + pub fn push(&mut self, symbol: S) { + self.store.push(symbol); + } /// Returns an owned reference to the current symbol on the tape pub fn read(&self) -> Result<&S, FsmError> { self.get(self.pos) @@ -54,9 +94,36 @@ impl Tape { } } + pub fn write_iter(&mut self, iter: impl Iterator) { + for (i, symbol) in iter.enumerate() { + if i < self.store.len() { + self.store[i] = symbol; + } else { + self.store.push(symbol); + } + } + } + + pub fn shift(self, direction: Direction) -> Self { + self.on_update(); + Self { + pos: direction.apply(self.pos), + store: self.store, + ticks: self.ticks, + } + } + + pub fn shift_left(self) -> Self { + self.shift(Direction::Left) + } + + pub fn shift_right(self) -> Self { + self.shift(Direction::Right) + } + pub fn step(&mut self, direction: Direction) { self.pos = direction.apply(self.pos); - self.ticks += 1; + self.on_update(); } pub fn step_left(&mut self) { @@ -67,22 +134,20 @@ impl Tape { self.step(Direction::Right); } - pub fn print_tape(&self) - where - S: core::fmt::Display, - { - println!( - "{}", - self.store - .iter() - .enumerate() - .map(|(i, c)| if i == self.pos { - format!("[{}]", &c) - } else { - c.to_string() - }) - .collect::() - ); + pub fn update(&mut self, tail: Tail) -> State { + let Tail { + direction, + state, + symbol, + } = tail; + self.write(symbol); + self.step(direction); + self.on_update(); + state + } + + fn on_update(&self) { + self.ticks.set(self.ticks.get() + 1); } } @@ -91,28 +156,54 @@ impl Tape { Tape { pos: 0, store: input.chars().collect(), - ticks: 0, + ticks: Cell::default(), } } } -impl core::fmt::Display for Tape +impl AsRef<[S]> for Tape { + fn as_ref(&self) -> &[S] { + &self.store + } +} + +impl AsMut<[S]> for Tape { + fn as_mut(&mut self) -> &mut [S] { + &mut self.store + } +} + +impl core::borrow::Borrow<[S]> for Tape { + fn borrow(&self) -> &[S] { + &self.store + } +} + +impl core::borrow::BorrowMut<[S]> for Tape { + fn borrow_mut(&mut self) -> &mut [S] { + &mut self.store + } +} + +impl core::ops::Deref for Tape { + type Target = [S]; + + fn deref(&self) -> &Self::Target { + &self.store + } +} + +impl core::ops::DerefMut for Tape { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.store + } +} + +impl core::fmt::Display for Tape where - T: core::fmt::Display, + S: alloc::string::ToString, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!( - f, - "{}", - self.store - .iter() - .enumerate() - .map(|(i, c)| if i == self.pos { - format!("[{}]", &c) - } else { - c.to_string() - }) - .collect::() - ) + write!(f, "{}", self.to_string()) } } From 07c3cd648b02900c8a7a7272ff9826f1e05a4382 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 23 Jul 2024 14:33:10 -0500 Subject: [PATCH 2/4] update --- rstm/Cargo.toml | 2 +- rstm/examples/basic.rs | 28 ++++++++++++ rstm/examples/default.rs | 34 --------------- rstm/src/lib.rs | 11 +---- rstm/src/macros.rs | 2 +- rstm/src/rules/mod.rs | 1 - rstm/src/rules/program.rs | 9 ++-- rstm/src/seal.rs | 2 +- rstm/src/state/mod.rs | 6 +-- rstm/src/state/state.rs | 1 - rstm/src/state/states/binary.rs | 9 +++- rstm/src/state/states/halting.rs | 4 +- rstm/src/traits/stateful.rs | 4 -- rstm/src/traits/symbolic.rs | 11 +++-- rstm/src/turing/context.rs | 12 ++++-- rstm/src/turing/mod.rs | 14 ++++-- rstm/src/turing/{machine.rs => model.rs} | 55 ++++++++++++++++-------- rstm/src/types/direction.rs | 39 +++++++++++++---- rstm/src/types/mod.rs | 1 - rstm/src/types/symbol.rs | 12 +++--- rstm/src/types/tape.rs | 31 ++++++------- 21 files changed, 163 insertions(+), 125 deletions(-) create mode 100644 rstm/examples/basic.rs delete mode 100644 rstm/examples/default.rs rename rstm/src/turing/{machine.rs => model.rs} (78%) diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 76349f8..3f35526 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -50,7 +50,7 @@ doctest = false test = true [[example]] -name = "default" +name = "basic" required-features = ["tracing"] [dependencies] diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs new file mode 100644 index 0000000..0f137b7 --- /dev/null +++ b/rstm/examples/basic.rs @@ -0,0 +1,28 @@ +/* + Appellation: default + Contrib: FL03 +*/ +extern crate rstm; + +use rstm::prelude::{Direction, Instruction, State, Tape, TM}; +use rstm::rule; +use rstm::state::binary::BinaryStates::*; + +// use Direction::Right; + +fn main() -> Result<(), Box> { + tracing_subscriber::fmt().init(); + let tape = Tape::from_str("1011"); + let initial_state = State(Invalid); + + let rules = vec![ + rule![(State(Invalid), '0') -> Right(State(Invalid), '1',)], + rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], + rule![(State(Valid), '0') -> Right(State(Valid), '1',)], + rule![(State(Valid), '1') -> Right(State(Valid), '0',)], + ]; + + let mut tm = TM::new(initial_state, rules, tape); + tm.run(); + Ok(()) +} diff --git a/rstm/examples/default.rs b/rstm/examples/default.rs deleted file mode 100644 index 4fe72b2..0000000 --- a/rstm/examples/default.rs +++ /dev/null @@ -1,34 +0,0 @@ -/* - Appellation: default - Contrib: FL03 -*/ -extern crate rstm; - -use rstm::rule; -use rstm::state::binary::BinaryStates::*; -use rstm::prelude::{Direction, Fsm, Instruction, State, Tape}; - -use Direction::Right; - -lazy_static::lazy_static! { - static ref RULESET: Vec> = vec![ - rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], - rule![(State(Invalid), '1') -> Right(State(Valid), '0',)], - rule![(State(Invalid), '0') -> Right(State(Valid), '1',)], - rule![(State(Valid), '1') -> Right(State(Invalid), '0',)], - ]; -} - -fn main() -> Result<(), Box> { - tracing_subscriber::fmt().init(); - let tape = Tape::from_str("1011"); - let initial_state = State(Invalid); - - let rules = vec![ - - ]; - - let mut tm = Fsm::new(initial_state, RULESET.clone(), tape); - tm.run(); - Ok(()) -} diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index df1150c..5ad8580 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -4,21 +4,14 @@ */ //! # rstm //! -//!## Turing Machine -//! -//! ### Overview -//! -//! A Turing machine is a mathematical model describing the generalization of computation using -//! a set of symbols and a [tape](Tape). Assuming an infinite tape, the machine can read, write, and move linearly -//! across the tape. The machine uses a set of pre-defined rules to determine the next state and symbol. -//! + #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] extern crate alloc; #[doc(inline)] -pub use self::{error::FsmError, state::State, traits::prelude::*, turing::Fsm, types::prelude::*}; +pub use self::{error::FsmError, state::State, traits::prelude::*, turing::TM, types::prelude::*}; #[macro_use] pub(crate) mod macros; diff --git a/rstm/src/macros.rs b/rstm/src/macros.rs index 20b768e..12225e2 100644 --- a/rstm/src/macros.rs +++ b/rstm/src/macros.rs @@ -21,4 +21,4 @@ macro_rules! ruleset { ($($($rule:tt)*);* $(,)?) => { vec![$(rule!($($rule)*)),*] }; -} \ No newline at end of file +} diff --git a/rstm/src/rules/mod.rs b/rstm/src/rules/mod.rs index 36dbdc4..a4c5440 100644 --- a/rstm/src/rules/mod.rs +++ b/rstm/src/rules/mod.rs @@ -12,4 +12,3 @@ pub(crate) mod prelude { pub use super::instruction::Instruction; pub use super::program::Program; } - diff --git a/rstm/src/rules/program.rs b/rstm/src/rules/program.rs index a09b997..d594851 100644 --- a/rstm/src/rules/program.rs +++ b/rstm/src/rules/program.rs @@ -12,7 +12,6 @@ use std::collections::{hash_set as set, HashSet as Set}; type RuleSet = Set>; - #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { @@ -58,7 +57,11 @@ impl Program { self.instructions.iter() } /// Returns an owned reference to the element(s) specified by the index. - pub fn get(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq { + pub fn get(&self, head: &Head) -> Option<&Tail> + where + Q: PartialEq, + S: PartialEq, + { self.iter().find(|i| i.head() == head).map(|i| i.tail()) } } @@ -75,8 +78,6 @@ impl Program { instructions: RuleSet::from_iter(instructions), } } - - } #[cfg(all(feature = "alloc", not(feature = "std")))] impl Program { diff --git a/rstm/src/seal.rs b/rstm/src/seal.rs index cfd0159..c419d9b 100644 --- a/rstm/src/seal.rs +++ b/rstm/src/seal.rs @@ -7,7 +7,7 @@ //! that cannot be implemented outside of our own crate. This way we //! can feel free to extend those traits without worrying about it //! being a breaking change for other implementations. -//! +//! #[doc(hidden)] pub(crate) trait Private {} diff --git a/rstm/src/state/mod.rs b/rstm/src/state/mod.rs index 047c285..2057b91 100644 --- a/rstm/src/state/mod.rs +++ b/rstm/src/state/mod.rs @@ -25,9 +25,8 @@ pub(crate) mod prelude { pub use super::states::prelude::*; } -/// -pub trait Mode { -} +/// +pub trait Mode {} pub trait Haltable { fn halt(&self) -> bool; @@ -57,4 +56,3 @@ impl Haltable for &str { matches!(s.as_str(), "h" | "H" | "stop" | "terminate") } } - diff --git a/rstm/src/state/state.rs b/rstm/src/state/state.rs index 74f52ba..a6c3475 100644 --- a/rstm/src/state/state.rs +++ b/rstm/src/state/state.rs @@ -3,7 +3,6 @@ Contrib: FL03 */ - #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[repr(transparent)] diff --git a/rstm/src/state/states/binary.rs b/rstm/src/state/states/binary.rs index 280cc42..444f5f5 100644 --- a/rstm/src/state/states/binary.rs +++ b/rstm/src/state/states/binary.rs @@ -70,8 +70,6 @@ impl BinaryState { Self::Valid(_) => BinaryStates::Valid, } } - - } impl BinaryState { @@ -86,6 +84,13 @@ impl BinaryState { (self.kind(), self.as_ref()) } } + +impl Default for BinaryStates { + fn default() -> Self { + Self::Invalid + } +} + impl AsRef for BinaryState { fn as_ref(&self) -> &Q { match self { diff --git a/rstm/src/state/states/halting.rs b/rstm/src/state/states/halting.rs index 8e4f081..245d636 100644 --- a/rstm/src/state/states/halting.rs +++ b/rstm/src/state/states/halting.rs @@ -7,6 +7,4 @@ pub trait PowerMode { private!(); } -pub enum On { - -} \ No newline at end of file +pub enum On {} diff --git a/rstm/src/traits/stateful.rs b/rstm/src/traits/stateful.rs index c5d16c0..fcfef50 100644 --- a/rstm/src/traits/stateful.rs +++ b/rstm/src/traits/stateful.rs @@ -3,7 +3,6 @@ Contrib: FL03 */ - /// S pub trait BaseState { type Data; @@ -13,11 +12,8 @@ pub trait BaseState { fn data_mut(&mut self) -> &mut Self::Data; fn set_data(&mut self, data: Self::Data); - - } - /// [Stateful] is used to describe objects which rely upon a state. /// pub trait Stateful { diff --git a/rstm/src/traits/symbolic.rs b/rstm/src/traits/symbolic.rs index b9910e8..660eeb8 100644 --- a/rstm/src/traits/symbolic.rs +++ b/rstm/src/traits/symbolic.rs @@ -13,7 +13,6 @@ pub trait AsRefChar { fn as_char(&self) -> &char; } - pub trait Symbol { fn as_ptr(&self) -> *const char; @@ -26,7 +25,10 @@ pub trait Symbolic: Eq + Ord + core::fmt::Debug + core::fmt::Display + core::has ************* Implementations ************* */ -impl AsRefChar for T where T: AsRef { +impl AsRefChar for T +where + T: AsRef, +{ fn as_char(&self) -> &char { self.as_ref() } @@ -50,4 +52,7 @@ impl Symbol for char { } } -impl Symbolic for S where S: Symbol + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash {} \ No newline at end of file +impl Symbolic for S where + S: Symbol + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash +{ +} diff --git a/rstm/src/turing/context.rs b/rstm/src/turing/context.rs index 6c4ce9c..ba3b67c 100644 --- a/rstm/src/turing/context.rs +++ b/rstm/src/turing/context.rs @@ -21,17 +21,23 @@ impl Context { } /// pub fn from_program(program: Program) -> Self { - Self { program, state: None } + Self { + program, + state: None, + } } - pub fn from_state(state: State) -> Self where Q: Default, S: Default { + pub fn from_state(state: State) -> Self + where + Q: Default, + S: Default, + { Self { program: Program::default(), state: Some(state), } } - /// Returns the current state of the system; /// if the state is [none](Option::None), assumes the initial state. pub fn current_state(&self) -> &State { diff --git a/rstm/src/turing/mod.rs b/rstm/src/turing/mod.rs index 65a9106..99f0698 100644 --- a/rstm/src/turing/mod.rs +++ b/rstm/src/turing/mod.rs @@ -2,15 +2,23 @@ Appellation: turing Contrib: FL03 */ +//!## Turing Machine +//! +//! ### Overview +//! +//! A Turing machine is a mathematical model describing the generalization of computation using +//! a set of symbols and a [tape](Tape). Assuming an infinite tape, the machine can read, write, and move linearly +//! across the tape. The machine uses a set of pre-defined rules to determine the next state and symbol. +//! #[doc(inline)] -pub use self::{actor::Actor, context::Context, machine::Fsm}; +pub use self::{actor::Actor, context::Context, model::TM}; pub(crate) mod actor; pub(crate) mod context; -pub(crate) mod machine; +pub(crate) mod model; pub(crate) mod prelude { - pub use super::machine::Fsm; + pub use super::model::TM; } #[doc(hidden)] diff --git a/rstm/src/turing/machine.rs b/rstm/src/turing/model.rs similarity index 78% rename from rstm/src/turing/machine.rs rename to rstm/src/turing/model.rs index 16271d4..27748de 100644 --- a/rstm/src/turing/machine.rs +++ b/rstm/src/turing/model.rs @@ -9,18 +9,17 @@ use crate::rules::Instruction; use crate::state::{Haltable, State}; use crate::Symbolic; -/// # Finite State Machine -/// - -#[derive(Clone, Debug,)] +/// # Turing Machine ([TM]) +/// +#[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Fsm { +pub struct TM { pub(crate) ctx: Context, pub(crate) registry: Registry, pub(crate) tape: Tape, } -impl Fsm { +impl TM { pub const fn context(&self) -> &Context { &self.ctx } @@ -29,7 +28,11 @@ impl Fsm { self.context().current_state() } - pub fn head(&self) -> Head where Q: Clone, S: Clone { + pub fn head(&self) -> Head + where + Q: Clone, + S: Clone, + { let state = self.current_state().clone(); let symbol = self.tape.read().unwrap().clone(); Head::new(state, symbol) @@ -52,33 +55,42 @@ impl Fsm { } } - #[cfg(feature = "std")] -impl Fsm +impl TM where Q: Eq + core::hash::Hash, - S: Symbolic + S: Symbolic, { pub fn new( initial_state: State, instructions: impl IntoIterator>, tape: Tape, - - ) -> Self where Q: Clone + Default, S: Clone + Default { + ) -> Self + where + Q: Clone + Default, + S: Clone + Default, + { let ctx = Context::from_state(initial_state.clone()); let mut registry = Registry::new(); for t in instructions { registry.insert(t.head, t.tail); } - Fsm { + TM { ctx, tape, registry, } } - #[cfg_attr(feature = "tracing", tracing::instrument(skip_all, name = "step", target = "fsm"))] - pub fn step(&mut self) -> Result<(), FsmError> where Q: Clone, S: Clone { + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "fsm") + )] + pub fn step(&mut self) -> Result<(), FsmError> + where + Q: Clone, + S: Clone, + { #[cfg(feature = "tracing")] tracing::info!("Stepping..."); let registry = self.registry.clone(); @@ -93,8 +105,15 @@ where } Err(FsmError::state_not_found("")) } - #[cfg_attr(feature = "tracing", tracing::instrument(skip_all, name = "run", target = "fsm"))] - pub fn run(mut self) -> Result<(), FsmError> where Q: Clone, S: Clone { + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "run", target = "fsm") + )] + pub fn run(mut self) -> Result<(), FsmError> + where + Q: Clone, + S: Clone, + { #[cfg(feature = "tracing")] tracing::info!("Running the program..."); loop { @@ -110,7 +129,7 @@ where } } -impl Fsm +impl TM where Q: Clone + Eq + core::hash::Hash + Haltable, { diff --git a/rstm/src/types/direction.rs b/rstm/src/types/direction.rs index 40ac0e4..effb003 100644 --- a/rstm/src/types/direction.rs +++ b/rstm/src/types/direction.rs @@ -132,17 +132,38 @@ impl Direction { } } -impl From for Direction { - fn from(value: i8) -> Self { - match value % 2 { - -1 => Self::Left, - 0 => Self::Stay, - 1 => Self::Right, - _ => Self::Stay, - } - } +macro_rules! impl_from_direction { + ($($T:ty),*) => { + $( + impl From<$T> for Direction { + fn from(value: $T) -> Self { + match value % 3 { + 0 => Self::Stay, + 1 => Self::Right, + _ => Self::Left, + } + } + } + )* + }; + (signed: $($T:ty),*) => { + $( + impl From<$T> for Direction { + fn from(value: $T) -> Self { + match value % 2 { + -1 => Self::Left, + 1 => Self::Right, + _ => Self::Stay, + } + } + } + )* + }; } +impl_from_direction!(u8, u16, u32, u64, u128, usize); +impl_from_direction!(signed: i8, i16, i32, i64, i128, isize); + impl From for Direction { fn from(value: char) -> Self { match value { diff --git a/rstm/src/types/mod.rs b/rstm/src/types/mod.rs index 4029150..9e822b9 100644 --- a/rstm/src/types/mod.rs +++ b/rstm/src/types/mod.rs @@ -9,7 +9,6 @@ pub mod direction; pub mod head; #[doc(hidden)] pub mod scope; -#[doc(hidden)] pub mod symbol; pub mod tail; pub mod tape; diff --git a/rstm/src/types/symbol.rs b/rstm/src/types/symbol.rs index cecf9c4..b82975e 100644 --- a/rstm/src/types/symbol.rs +++ b/rstm/src/types/symbol.rs @@ -2,13 +2,13 @@ Appellation: symbol Contrib: FL03 */ +use crate::Symbol; #[cfg(feature = "alloc")] use alloc::vec::Vec; -#[repr(transparent)] -pub struct Symbol(pub S); - - -pub struct Alphabet { - pub symbols: Vec>, +pub struct InputAlpha +where + S: Symbol, +{ + pub symbols: Vec, } diff --git a/rstm/src/types/tape.rs b/rstm/src/types/tape.rs index e1bec9f..eecb317 100644 --- a/rstm/src/types/tape.rs +++ b/rstm/src/types/tape.rs @@ -8,7 +8,6 @@ use core::cell::Cell; #[allow(unused)] #[doc(hidden)] pub struct Slider { - scope: usize, state: *const State, } @@ -50,23 +49,15 @@ impl Tape { self.store.get(idx) } + pub fn ticks(&self) -> usize { + self.ticks.get() + } + pub fn to_string(&self) -> String where - S: alloc::string::ToString, + S: core::fmt::Display, { - format!( - "{}", - self.store - .iter() - .enumerate() - .map(|(i, c)| { - match i { - c if i == self.pos => format!("[{}]", &c), - _ => c.to_string(), - } - }) - .collect::() - ) + format!("step ({}): {}", self.ticks(), self) } /// Removes and returns the last element of the tape, or `None` if it is empty. pub fn pop(&mut self) -> Option { @@ -201,9 +192,15 @@ impl core::ops::DerefMut for Tape { impl core::fmt::Display for Tape where - S: alloc::string::ToString, + S: core::fmt::Display, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{}", self.to_string()) + for (i, c) in self.store.iter().enumerate() { + match c { + b if i == self.pos => write!(f, "[{b}]")?, + _ => write!(f, "{c}")?, + } + } + Ok(()) } } From c4f58dffb80056386d5703f7bb7d203cf66f090b Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 23 Jul 2024 15:05:01 -0500 Subject: [PATCH 3/4] update --- rstm/Cargo.toml | 24 +++++----- rstm/examples/basic.rs | 2 +- rstm/src/lib.rs | 7 ++- rstm/src/rules/program.rs | 95 ++++++++++++++++++------------------- rstm/src/state/mod.rs | 2 - rstm/src/traits/stateful.rs | 5 +- rstm/src/turing/model.rs | 73 ++++++++++------------------ rstm/src/types/symbol.rs | 2 - rstm/src/types/tape.rs | 20 +++++++- 9 files changed, 109 insertions(+), 121 deletions(-) diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 3f35526..f50ff32 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -13,9 +13,7 @@ repository.workspace = true version.workspace = true [features] -default = [ - "std", -] +default = [] full = [ "default", @@ -24,9 +22,9 @@ full = [ ] # [FF] Dependencies -alloc = [ - "serde?/alloc", -] +# alloc = [ +# "serde?/alloc", +# ] serde = [ "dep:serde", @@ -37,11 +35,11 @@ tracing = [ ] # ********* [FF] Environments ********* -std = [ - "alloc", - "serde?/std", - "strum/std", -] +# std = [ +# "alloc", +# "serde?/std", +# "strum/std", +# ] [lib] bench = true @@ -61,13 +59,13 @@ lazy_static = "1" tracing-subscriber = { features = [], version = "0.3" } [dependencies.serde] -default-features = false +# default-features = false features = ["derive"] optional = true version = "1" [dependencies.strum] -default-features = false +# default-features = false features = ["derive"] version = "0.26" diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 0f137b7..6d8f5bf 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -23,6 +23,6 @@ fn main() -> Result<(), Box> { ]; let mut tm = TM::new(initial_state, rules, tape); - tm.run(); + tm.run()?; Ok(()) } diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 5ad8580..9dab738 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -5,10 +5,9 @@ //! # rstm //! -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "alloc")] -extern crate alloc; +// #![cfg_attr(not(feature = "std"), no_std)] +// #[cfg(feature = "alloc")] +// extern crate alloc; #[doc(inline)] pub use self::{error::FsmError, state::State, traits::prelude::*, turing::TM, types::prelude::*}; diff --git a/rstm/src/rules/program.rs b/rstm/src/rules/program.rs index d594851..8a2f111 100644 --- a/rstm/src/rules/program.rs +++ b/rstm/src/rules/program.rs @@ -4,13 +4,9 @@ */ use super::Instruction; use crate::{Head, State, Tail}; +use std::vec; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use alloc::collections::{btree_set as set, BTreeSet as Set}; -#[cfg(feature = "std")] -use std::collections::{hash_set as set, HashSet as Set}; - -type RuleSet = Set>; +type RuleSet = Vec>; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -26,6 +22,16 @@ impl Program { instructions: RuleSet::new(), } } + + pub fn from_instructions(instructions: impl IntoIterator>) -> Self + where + Q: Default, + { + Self { + initial_state: State::default(), + instructions: RuleSet::from_iter(instructions), + } + } /// pub fn with_initial_state(self, initial_state: State) -> Self { Self { @@ -34,12 +40,22 @@ impl Program { } } - pub fn with_instructions(self, instructions: RuleSet) -> Self { + pub fn with_instructions( + self, + instructions: impl IntoIterator>, + ) -> Self { Self { - instructions, + instructions: RuleSet::from_iter(instructions), ..self } } + /// Returns an owned reference to the element(s) specified by the index. + pub fn get(&self, idx: I) -> Option<&I::Output> + where + I: core::slice::SliceIndex<[Instruction]>, + { + self.instructions.get(idx) + } /// Returns an owned reference to the initial state of the program. pub const fn initial_state(&self) -> &State { &self.initial_state @@ -53,68 +69,51 @@ impl Program { &mut self.instructions } /// Returns an iterator over the elements. - pub fn iter(&self) -> set::Iter> { + pub fn iter(&self) -> core::slice::Iter> { self.instructions.iter() } - /// Returns an owned reference to the element(s) specified by the index. - pub fn get(&self, head: &Head) -> Option<&Tail> + /// Returns a collection of tails for a given head. + pub fn get_head(&self, head: &Head) -> Vec<&Tail> where Q: PartialEq, S: PartialEq, { - self.iter().find(|i| i.head() == head).map(|i| i.tail()) + self.iter() + .filter_map(|i| { + if i.head() == head { + Some(i.tail()) + } else { + None + } + }) + .collect() } } -#[cfg(feature = "std")] -impl Program { - pub fn from_instructions(instructions: impl IntoIterator>) -> Self - where - Q: Default + Eq + core::hash::Hash, - S: Default + Eq + core::hash::Hash, - { +impl From> for Program { + fn from(instructions: RuleSet) -> Self { Self { initial_state: State::default(), - instructions: RuleSet::from_iter(instructions), + instructions, } } } -#[cfg(all(feature = "alloc", not(feature = "std")))] -impl Program { - pub fn from_instructions(instructions: impl IntoIterator>) -> Self - where - Q: Default + Ord, - S: Default + Ord, - { + +impl FromIterator> for Program +where + Q: Default, +{ + fn from_iter>>(iter: I) -> Self { Self { initial_state: State::default(), - instructions: RuleSet::from_iter(instructions), + instructions: RuleSet::from_iter(iter), } } - - pub fn iter(&self) -> set::Iter> { - self.instructions.iter() - } - - pub fn iter_mut(&mut self) -> set::IterMut> { - self.instructions.iter_mut() - } -} - -#[cfg(feature = "std")] -impl IntoIterator for Program { - type Item = Instruction; - type IntoIter = set::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.instructions.into_iter() - } } -#[cfg(all(feature = "alloc", not(feature = "std")))] impl IntoIterator for Program { type Item = Instruction; - type IntoIter = set::IntoIter; + type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.instructions.into_iter() diff --git a/rstm/src/state/mod.rs b/rstm/src/state/mod.rs index 2057b91..55d01c6 100644 --- a/rstm/src/state/mod.rs +++ b/rstm/src/state/mod.rs @@ -26,8 +26,6 @@ pub(crate) mod prelude { } /// -pub trait Mode {} - pub trait Haltable { fn halt(&self) -> bool; } diff --git a/rstm/src/traits/stateful.rs b/rstm/src/traits/stateful.rs index fcfef50..5f6ec4b 100644 --- a/rstm/src/traits/stateful.rs +++ b/rstm/src/traits/stateful.rs @@ -11,7 +11,10 @@ pub trait BaseState { fn data_mut(&mut self) -> &mut Self::Data; - fn set_data(&mut self, data: Self::Data); + #[doc(hidden)] + fn swap(&mut self, state: S::Data) -> S + where + S: BaseState; } /// [Stateful] is used to describe objects which rely upon a state. diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index 27748de..dca82c5 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -4,10 +4,9 @@ */ use super::Context; -use crate::prelude::{FsmError, Head, Registry, Tape}; -use crate::rules::Instruction; +use crate::prelude::{FsmError, Head, Registry, Symbolic, Tape}; +use crate::rules::{Instruction, Program}; use crate::state::{Haltable, State}; -use crate::Symbolic; /// # Turing Machine ([TM]) /// @@ -15,11 +14,24 @@ use crate::Symbolic; #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct TM { pub(crate) ctx: Context, - pub(crate) registry: Registry, pub(crate) tape: Tape, } impl TM { + pub fn new( + initial_state: State, + instructions: impl IntoIterator>, + tape: Tape, + ) -> Self + where + Q: Clone, + S: Clone + Default, + { + let program = Program::new(initial_state.clone()).with_instructions(instructions); + let ctx = Context::new(program, initial_state); + TM { ctx, tape } + } + pub const fn context(&self) -> &Context { &self.ctx } @@ -37,14 +49,6 @@ impl TM { let symbol = self.tape.read().unwrap().clone(); Head::new(state, symbol) } - /// - pub const fn registry(&self) -> &Registry { - &self.registry - } - - pub fn registry_mut(&mut self) -> &mut Registry { - &mut self.registry - } pub const fn tape(&self) -> &Tape { &self.tape @@ -55,51 +59,26 @@ impl TM { } } -#[cfg(feature = "std")] +// #[cfg(feature = "std")] impl TM where - Q: Eq + core::hash::Hash, - S: Symbolic, + Q: Clone + PartialEq, + S: Clone + Symbolic, { - pub fn new( - initial_state: State, - instructions: impl IntoIterator>, - tape: Tape, - ) -> Self - where - Q: Clone + Default, - S: Clone + Default, - { - let ctx = Context::from_state(initial_state.clone()); - let mut registry = Registry::new(); - for t in instructions { - registry.insert(t.head, t.tail); - } - - TM { - ctx, - tape, - registry, - } - } #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "step", target = "fsm") )] - pub fn step(&mut self) -> Result<(), FsmError> - where - Q: Clone, - S: Clone, - { + pub fn step(&mut self) -> Result<(), FsmError> { #[cfg(feature = "tracing")] tracing::info!("Stepping..."); - let registry = self.registry.clone(); + let prog = self.ctx.program.clone(); // Get a clone of the current state let cst = self.current_state().clone(); let sym = self.tape().read()?.clone(); let head = Head::new(cst.clone(), sym); - if let Some(tail) = registry.get(&head).cloned() { - let nxt = self.tape.update(tail); + if let Some(tail) = prog.get_head(&head).first().cloned() { + let nxt = self.tape.update_inplace(tail.clone()); self.ctx.set_state(nxt); return Ok(()); } @@ -109,11 +88,7 @@ where feature = "tracing", tracing::instrument(skip_all, name = "run", target = "fsm") )] - pub fn run(mut self) -> Result<(), FsmError> - where - Q: Clone, - S: Clone, - { + pub fn run(mut self) -> Result<(), FsmError> { #[cfg(feature = "tracing")] tracing::info!("Running the program..."); loop { diff --git a/rstm/src/types/symbol.rs b/rstm/src/types/symbol.rs index b82975e..43ab3d5 100644 --- a/rstm/src/types/symbol.rs +++ b/rstm/src/types/symbol.rs @@ -3,8 +3,6 @@ Contrib: FL03 */ use crate::Symbol; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; pub struct InputAlpha where diff --git a/rstm/src/types/tape.rs b/rstm/src/types/tape.rs index eecb317..3c4ae28 100644 --- a/rstm/src/types/tape.rs +++ b/rstm/src/types/tape.rs @@ -5,6 +5,8 @@ use crate::{Direction, FsmError, State, Tail}; use core::cell::Cell; +use super::Head; + #[allow(unused)] #[doc(hidden)] pub struct Slider { @@ -125,7 +127,23 @@ impl Tape { self.step(Direction::Right); } - pub fn update(&mut self, tail: Tail) -> State { + pub fn update(self, tail: Tail) -> (Self, Head) + where + S: Clone, + { + let Tail { + direction, + state, + symbol, + } = tail; + let mut tape = self; + tape.write(symbol.clone()); + tape.step(direction); + tape.on_update(); + (tape, Head::new(state, symbol)) + } + + pub fn update_inplace(&mut self, tail: Tail) -> State { let Tail { direction, state, From 430ce6e325a81d2cd1a3a47b781b8e8ac9833138 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 23 Jul 2024 15:08:39 -0500 Subject: [PATCH 4/4] update --- rstm/examples/basic.rs | 6 +++--- rstm/src/turing/model.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 6d8f5bf..5f9ecb7 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,7 +4,7 @@ */ extern crate rstm; -use rstm::prelude::{Direction, Instruction, State, Tape, TM}; +use rstm::prelude::{State, Tape, TM}; use rstm::rule; use rstm::state::binary::BinaryStates::*; @@ -12,7 +12,7 @@ use rstm::state::binary::BinaryStates::*; fn main() -> Result<(), Box> { tracing_subscriber::fmt().init(); - let tape = Tape::from_str("1011"); + let tape = Tape::from_str("10111000101001101011010010"); let initial_state = State(Invalid); let rules = vec![ @@ -22,7 +22,7 @@ fn main() -> Result<(), Box> { rule![(State(Valid), '1') -> Right(State(Valid), '0',)], ]; - let mut tm = TM::new(initial_state, rules, tape); + let tm = TM::new(initial_state, rules, tape); tm.run()?; Ok(()) } diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index dca82c5..c3b5e42 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -4,7 +4,7 @@ */ use super::Context; -use crate::prelude::{FsmError, Head, Registry, Symbolic, Tape}; +use crate::prelude::{FsmError, Head, Symbolic, Tape}; use crate::rules::{Instruction, Program}; use crate::state::{Haltable, State};