From 68998d08f703dc0946026eb503794b753d567da2 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 10:31:42 -0500 Subject: [PATCH 01/35] v0.0.3 Signed-off-by: Joe McCain III --- Cargo.toml | 2 +- rstm/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 868998c..34351af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ keywords = [ ] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rstm.git" -version = "0.0.2" +version = "0.0.3" [profile.dev] opt-level = 0 diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index 68d92b4..cdd9878 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -63,7 +63,7 @@ thiserror.workspace = true [dependencies.rstm-core] path = "../core" -version = "0.0.2" +version = "0.0.3" [dependencies.serde] # default-features = false From 01b79ea156714d608c8e75790b84f1819872264d Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 10:32:54 -0500 Subject: [PATCH 02/35] update Signed-off-by: Joe McCain III --- .github/workflows/crates.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml index 3673993..0fb4898 100644 --- a/.github/workflows/crates.yml +++ b/.github/workflows/crates.yml @@ -16,7 +16,7 @@ on: workflow_dispatch: jobs: - independents: + base: env: CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.suffix }} name: Publish (${{ matrix.suffix }}) @@ -42,6 +42,7 @@ jobs: - run: cargo publish --all-features -v -p ${{ env.CRATE_NAME }} --token ${{ secrets.CARGO_REGISTRY_TOKEN }} publish: name: Publish (${{ github.event.repository.name }}) + needs: base runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From ba10f0d5f95122b32873b3f73d2d0b78ce2be924 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 10:43:18 -0500 Subject: [PATCH 03/35] update Signed-off-by: Joe McCain III --- core/src/rules/parts/head.rs | 4 ++-- rstm/examples/basic.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/rules/parts/head.rs b/core/src/rules/parts/head.rs index 3fb272e..1b6ce7d 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/rules/parts/head.rs @@ -4,8 +4,8 @@ */ 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::Tape). +/// The head of a turing machine generally speaks to the current state and symbol of the +/// machine w.r.t. the [tape](crate::Tape). #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Head { diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 1bc296a..37cec60 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -18,7 +18,7 @@ fn main() -> Result<(), Box> { let tape_data: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; let rules = vec![ - rule![(Invalid, 0) -> Left(Invalid, 0)], + rule![(Invalid, 0) -> Right(Invalid, 0)], rule![(Invalid, 1) -> Right(Valid, 0)], rule![(Valid, 0) -> Right(Valid, 1)], rule![(Valid, 1) -> Left(Valid, 0)], From 3dfaf3a941909a79b6ae529de2eacd45977d5cc2 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 10:50:09 -0500 Subject: [PATCH 04/35] update Signed-off-by: Joe McCain III --- core/src/ops/shift.rs | 3 +++ core/src/ops/transform.rs | 12 +++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/ops/shift.rs b/core/src/ops/shift.rs index e0e8f9e..ed14e56 100644 --- a/core/src/ops/shift.rs +++ b/core/src/ops/shift.rs @@ -3,6 +3,9 @@ Contrib: FL03 */ +/// [`Shift`] describes a generalized shift operation; +/// w.r.t. Turing machines, Moore (1990) describes a shift operation as a _movement_ of the +/// tape head pub trait Shift { type Output; diff --git a/core/src/ops/transform.rs b/core/src/ops/transform.rs index 4ec945c..c4ac584 100644 --- a/core/src/ops/transform.rs +++ b/core/src/ops/transform.rs @@ -3,14 +3,12 @@ Contrib: FL03 */ -/// The [`Transform`] trait generically describes objects capable of applying some transformation. -/// From a "rustic" point of view, the trait simply provides an additional reference point for -/// the `map` method, which is a method that applies a function to a value and returns a new value. -/// -/// [`Transform::transform`] is a method that takes a reference to `self` and a value of type `T` -/// and returns a value of type [`Transform::Output`]. +/// [`Transform`] is describes a binary operation capable of applying some transformation. +/// More commonly, the typical "rustic" manner of which an object is transformed is through +/// the [`map`] method, which applies a function to a value and returns a new value. pub trait Transform { type Output; - + /// [`Transform::transform`] is a method that takes a reference to `self` and a value of type + /// `T` and returns a value of type [`Transform::Output`]. fn transform(&self, delta: T) -> Self::Output; } From 7c80e12165c5d3020f86f5bfe714c6395386044e Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 10:58:08 -0500 Subject: [PATCH 05/35] update Signed-off-by: Joe McCain III --- rstm/examples/basic.rs | 15 ++++++++------- rstm/src/turing/mod.rs | 17 +++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 37cec60..ebb9d1f 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -6,26 +6,27 @@ extern crate rstm; use rstm::{ rule, - state::{self, State}, StdTape, TM, }; -use state::BinState::*; +use rstm::state::BinState::*; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); - println!("{}", -1_isize as u8); - let tape_data: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + // initialize the tape data + let alpha: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + // define the rules for the machine let rules = vec![ rule![(Invalid, 0) -> Right(Invalid, 0)], rule![(Invalid, 1) -> Right(Valid, 0)], rule![(Valid, 0) -> Right(Valid, 1)], rule![(Valid, 1) -> Left(Valid, 0)], ]; - - let tape = StdTape::from_iter(tape_data); - let tm = TM::new(State(Invalid), rules, tape); + + let tape = StdTape::from_iter(alpha); + // create a new instance of the machine + let tm = TM::new(rstm::State(Invalid), rules, tape); tm.run()?; Ok(()) } diff --git a/rstm/src/turing/mod.rs b/rstm/src/turing/mod.rs index 6981970..c9b33e9 100644 --- a/rstm/src/turing/mod.rs +++ b/rstm/src/turing/mod.rs @@ -20,16 +20,13 @@ pub(crate) mod prelude { pub use super::model::TM; } -#[doc(hidden)] -pub trait Turing { - type Alpha; // input alphabet - type Beta; // output alphabet - type Gamma; // -} +use crate::prelude::Alphabet; -pub trait Ctx {} -pub trait Actor { - type Ctx; +#[doc(hidden)] +pub trait Turing { + type Alpha: Alphabet; // input alphabet + type Beta: Alphabet; // output alphabet + - fn handle(&self, context: Context) -> Result<(), Box>; + fn step(&self, input: Self::Alpha) -> Self::Beta; } From 676fd5d670f4a486da9e25ff0a996d8916382df2 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 11:10:46 -0500 Subject: [PATCH 06/35] update Signed-off-by: Joe McCain III --- README.md | 21 ++++++++++++++++++++- core/src/tape/tape.rs | 2 +- core/src/types/direction.rs | 8 ++------ rstm/examples/basic.rs | 17 +++++++---------- rstm/examples/utm.rs | 27 ++++++++++++--------------- rstm/src/turing/model.rs | 22 ++++++++++++---------- 6 files changed, 54 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 891d9ac..040b262 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,27 @@ cargo build --features full -r --workspace ```rust extern crate rstm; - fn main() -> Result<(), Box> { + use rstm::{rule, Program, State, StdTape, TM}; + use rstm::state::BinState::{Invalid, Valid}; + fn main() -> Result<(), Box> { + tracing_subscriber::fmt().with_target(false).init(); + + // initialize the tape data + let alpha: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + // define the rules for the machine + let rules = vec![ + rule![(Invalid, 0) -> Right(Invalid, 0)], + rule![(Invalid, 1) -> Right(Valid, 0)], + rule![(Valid, 0) -> Right(Valid, 1)], + rule![(Valid, 1) -> Left(Valid, 0)], + ]; + + let tape = StdTape::from_iter(alpha); + let program = Program::new(State(Invalid)).with_instructions(rules); + // create a new instance of the machine + let tm = TM::new(program, tape); + tm.execute()?; Ok(()) } ``` diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index d9af628..c412a57 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -126,7 +126,7 @@ impl StdTape { fn shift(&mut self, direction: Direction) -> usize { self.on_update(); - self.cursor = direction.apply(self.cursor); + self.cursor = direction.apply(self.cursor) % self.store.len(); self.position() } diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 03ca96e..8230f9d 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -86,12 +86,8 @@ impl Direction { Self::Stay } /// Applies the shift to the given position in the [direction](Direction) specified by the current instance. - pub fn apply(&self, cur: usize) -> usize { - match self { - Self::Left => cur - 1, - Self::Right => cur + 1, - Self::Stay => cur, - } + pub fn apply(self, cur: usize) -> usize { + cur.wrapping_add_signed(self as isize) } /// Converts an [i8] value into a [`Direction`] by taking the modulus of the value. /// The function uses a modulator of 2 to determine the direction since there are diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index ebb9d1f..e289bc0 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,18 +4,14 @@ */ extern crate rstm; -use rstm::{ - rule, - StdTape, TM, -}; - -use rstm::state::BinState::*; +use rstm::{rule, Program, State, StdTape, TM}; +use rstm::state::BinState::{Invalid, Valid}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); // initialize the tape data - let alpha: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; // define the rules for the machine let rules = vec![ rule![(Invalid, 0) -> Right(Invalid, 0)], @@ -23,10 +19,11 @@ fn main() -> Result<(), Box> { rule![(Valid, 0) -> Right(Valid, 1)], rule![(Valid, 1) -> Left(Valid, 0)], ]; - + let tape = StdTape::from_iter(alpha); + let program = Program::new(State(Invalid)).with_instructions(rules); // create a new instance of the machine - let tm = TM::new(rstm::State(Invalid), rules, tape); - tm.run()?; + let tm = TM::new(program, tape); + tm.execute()?; Ok(()) } diff --git a/rstm/examples/utm.rs b/rstm/examples/utm.rs index a176e96..f2ba80f 100644 --- a/rstm/examples/utm.rs +++ b/rstm/examples/utm.rs @@ -4,30 +4,27 @@ */ extern crate rstm; -use rstm::{ - rule, - state::{self, State}, - StdTape, TM, -}; - -use state::BinState::*; +use rstm::{rule, Program, State, StdTape, TM}; +use rstm::state::BinState::{Invalid, Valid}; fn main() -> Result<(), Box> { - tracing_subscriber::fmt().with_level(true).init(); - tracing::info!("Example: Wolfram [2, 3] UTM"); - - let tape = StdTape::::from_iter([0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]); - let initial_state = State(Invalid); + tracing_subscriber::fmt().with_target(false).init(); + // initialize the tape data + let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + // define the rules for the machine let rules = vec![ rule![(Invalid, 0) -> Right(Invalid, 0)], rule![(Invalid, 1) -> Right(Valid, 0)], rule![(Valid, 0) -> Right(Valid, 1)], - rule![(Valid, 1) -> Right(Valid, 0)], + rule![(Valid, 1) -> Left(Valid, 0)], ]; - let tm = TM::new(initial_state, rules, tape); - tm.run()?; + let tape = StdTape::from_iter(alpha); + let program = Program::new(State(Invalid)).with_instructions(rules); + // create a new instance of the machine + let tm = TM::new(program, tape); + tm.execute()?; Ok(()) } diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index da916ae..41f29db 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ use crate::prelude::{Error, Head, StdTape, Symbolic}; -use crate::rules::{Instruction, Program}; +use crate::rules::Program; use crate::state::State; /// # Turing Machine ([TM]) @@ -21,16 +21,14 @@ pub struct TM { impl TM { pub fn new( - State(state): State, - instructions: impl IntoIterator>, + program: Program, tape: StdTape, ) -> Self where - Q: Clone, - S: Clone + Default, + Q: Clone + Default, + S: Default, { - let state = State(state); - let program = Program::new(state.clone()).with_instructions(instructions); + let state = program.initial_state().cloned(); TM { program, state, @@ -73,14 +71,18 @@ impl TM { pub fn tape_mut(&mut self) -> &mut StdTape { &mut self.tape } - /// Runs the program until the - /// + /// Runs the program until the + /// /// The program will continue to run until the current state is a halt state. #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "run", target = "fsm") )] - pub fn run(mut self) -> Result<(), Error> where Q: Clone + PartialEq, S: Symbolic { + pub fn execute(mut self) -> Result<(), Error> + where + Q: Clone + PartialEq, + S: Symbolic, + { #[cfg(feature = "tracing")] tracing::info!("Running the program..."); loop { From 22f86a38a4eeee7bd98e0c4085fa60d15bfc5954 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 11:45:34 -0500 Subject: [PATCH 07/35] update Signed-off-by: Joe McCain III --- Cargo.toml | 4 ++-- core/src/rules/mod.rs | 4 +++- core/src/rules/program.rs | 20 ++++++++++++++++---- core/src/tape/iter.rs | 5 +++++ core/src/tape/mod.rs | 20 +++++++++++++++++++- core/src/tape/slider.rs | 33 ++++++++++++++++++--------------- core/src/traits/actor.rs | 20 ++++++++++++++++++++ core/src/types/direction.rs | 13 ++++++++----- rstm/examples/basic.rs | 4 ++-- rstm/examples/utm.rs | 2 +- 10 files changed, 94 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 34351af..40a9b7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,11 +23,11 @@ thiserror = "1" [workspace.package] authors = ["Joe McCain III ",] -categories = [ ] +categories = [ "mathematics", "science", "simulation" ] description = "This crate focuses on building concrete implementations for Turing Machines." edition = "2021" homepage = "https://github.com/FL03/rstm/wiki" -keywords = [ ] +keywords = [ "turing", "turing-machine", "utm" ] license = "Apache-2.0" readme = "README.md" repository = "https://github.com/FL03/rstm.git" diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 737ecbc..deb3a0d 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -5,7 +5,7 @@ #[doc(inline)] pub use self::{ instruction::*, - parts::{Head, Tail}, + parts::*, program::*, }; @@ -20,6 +20,8 @@ pub mod parts { pub(crate) mod head; pub(crate) mod tail; + + pub type IndexedHead = Head; } pub(crate) mod prelude { diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index e3127e4..d06b390 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -16,10 +16,13 @@ pub struct Program { } impl Program { - pub fn new(State(initial_state): State) -> Self { + pub fn new() -> Self + where + Q: Default, + { Self { - initial_state: State(initial_state), - ruleset: RuleSet::new(), + initial_state: State::default(), + ruleset: Vec::new(), } } @@ -32,6 +35,13 @@ impl Program { ruleset: RuleSet::from_iter(instructions), } } + + pub fn from_state(State(initial_state): State) -> Self { + Self { + initial_state: State(initial_state), + ruleset: RuleSet::new(), + } + } /// pub fn with_initial_state(self, State(state): State) -> Self { Self { @@ -94,7 +104,9 @@ impl Program { Q: PartialEq, S: PartialEq, { - self.iter().find(|i| i.head().to_ref() == head).map(|i| i.tail()) + self.iter() + .find(|i| i.head().to_ref() == head) + .map(|i| i.tail()) } } diff --git a/core/src/tape/iter.rs b/core/src/tape/iter.rs index ebeb3cc..3ef9601 100644 --- a/core/src/tape/iter.rs +++ b/core/src/tape/iter.rs @@ -2,3 +2,8 @@ Appellation: iter Contrib: FL03 */ + +pub struct Iter<'a, T> { + tape: &'a T, + index: usize, +} \ No newline at end of file diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 56489c9..deb8e85 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -29,5 +29,23 @@ pub trait RawTape { fn as_slice(&self) -> &[Self::Elem]; } +pub trait Read { + type Elem; + + fn read(&self) -> &Self::Elem; +} + +pub trait Write { + type Elem; + + fn write(&mut self, value: Self::Elem); +} + #[doc(hidden)] -pub trait Tape {} +pub trait Tape: Read + Write { + fn len(&self) -> usize; + + fn is_empty(&self) -> bool; +} + + diff --git a/core/src/tape/slider.rs b/core/src/tape/slider.rs index 341e7eb..16a2336 100644 --- a/core/src/tape/slider.rs +++ b/core/src/tape/slider.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #![allow(dead_code)] -use crate::State; +use crate::{Head, State}; /// /// @@ -12,33 +12,36 @@ use crate::State; /// configuration consists of the inner state of the head, the symbol it is reading, /// and the contents of the tape. pub struct Slider { - pub(crate) state: State, // inner state of head - pub(crate) symbol: usize, // index of symbol - pub(crate) tape: Vec, // tape + pub(crate) head: Head, // head of the tape + /// state of the machine + pub(crate) tape: Vec, } impl Slider { pub fn new(State(state): State, tape: impl IntoIterator) -> Self { Self { - state: State(state), - symbol: 0, + head: Head::new(State(state), 0), tape: tape.into_iter().collect(), } } - + /// Returns an immutable reference to the head of the machine. + pub fn head(&self) -> &Head { + &self.head + } + /// Returns the current state of the machine. pub fn state(&self) -> State<&Q> { - self.state.to_ref() + self.head.state.to_ref() } - - pub fn symbol(&self) -> usize { - self.symbol + /// Returns the current position of the head on the tape. + pub fn pos(&self) -> usize { + self.head.symbol } - + /// Returns the current symbol being read by the head. pub fn read(&self) -> &S { - &self.tape[self.symbol] + &self.tape[self.pos()] } - + /// Writes a symbol to the tape at the current position of the head. pub fn write(&mut self, symbol: S) { - self.tape[self.symbol] = symbol; + self.tape[self.head.symbol] = symbol; } } diff --git a/core/src/traits/actor.rs b/core/src/traits/actor.rs index 879b201..1de89f9 100644 --- a/core/src/traits/actor.rs +++ b/core/src/traits/actor.rs @@ -2,6 +2,7 @@ Appellation: fsm Contrib: FL03 */ +use crate::Head; pub trait Automata { type Rule; @@ -16,3 +17,22 @@ pub enum Step { Right(T), Stay(T), } + +pub trait Tape { + type Symbol; + + fn read(&self) -> Self::Symbol; + + fn write(&mut self, symbol: Self::Symbol); + + fn step(&mut self, step: Step); +} + +pub struct Context { + pub head: Head, + pub tape: S, +} +pub struct Actor { + pub(crate) state: usize, + pub(crate) tape: Vec, +} \ No newline at end of file diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 8230f9d..9cc4238 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -85,10 +85,6 @@ impl Direction { pub fn stay() -> Self { Self::Stay } - /// Applies the shift to the given position in the [direction](Direction) specified by the current instance. - pub fn apply(self, cur: usize) -> usize { - cur.wrapping_add_signed(self as isize) - } /// Converts an [i8] value into a [`Direction`] by taking the modulus of the value. /// The function uses a modulator of 2 to determine the direction since there are /// only two actionable directions ([left](Direction::Left) and [right](Direction::Right)). @@ -99,7 +95,8 @@ impl Direction { _ => Self::Stay, } } - /// Converts a [char] value into a direction; matches the value to the corresponding [direction](Direction). + /// Converts a [char] value into a direction; matches the value to the corresponding + /// [direction](Direction). pub fn from_char(value: char) -> Self { match value { 'L' | 'l' => Self::Left, @@ -123,6 +120,12 @@ impl Direction { Self::Stay => 'S', } } + /// Applies the shift to the given position in the [direction](Direction) specified by the + /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) + /// method. + pub fn apply(self, cur: usize) -> usize { + cur.wrapping_add_signed(self as isize) + } } impl AsDirection for T diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index e289bc0..00b2fc5 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,8 +4,8 @@ */ extern crate rstm; -use rstm::{rule, Program, State, StdTape, TM}; use rstm::state::BinState::{Invalid, Valid}; +use rstm::{rule, Program, State, StdTape, TM}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); @@ -21,7 +21,7 @@ fn main() -> Result<(), Box> { ]; let tape = StdTape::from_iter(alpha); - let program = Program::new(State(Invalid)).with_instructions(rules); + let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine let tm = TM::new(program, tape); tm.execute()?; diff --git a/rstm/examples/utm.rs b/rstm/examples/utm.rs index f2ba80f..76f4d51 100644 --- a/rstm/examples/utm.rs +++ b/rstm/examples/utm.rs @@ -21,7 +21,7 @@ fn main() -> Result<(), Box> { ]; let tape = StdTape::from_iter(alpha); - let program = Program::new(State(Invalid)).with_instructions(rules); + let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine let tm = TM::new(program, tape); tm.execute()?; From 4917a9c587e758f2cbfb17f3cd15b1b9c153cd17 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 12:10:02 -0500 Subject: [PATCH 08/35] update Signed-off-by: Joe McCain III --- core/src/rules/parts/head.rs | 13 ++++++++ core/src/traits/actor.rs | 64 +++++++++++++++++++++++++++--------- rstm/src/turing/model.rs | 10 ++---- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/core/src/rules/parts/head.rs b/core/src/rules/parts/head.rs index 1b6ce7d..435c5f5 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/rules/parts/head.rs @@ -99,6 +99,19 @@ impl Head { } } +impl Head { + pub fn shift(self, direction: crate::Direction) -> Self { + Self { + symbol: direction.apply(self.symbol), + ..self + } + } + + pub fn shift_inplace(&mut self, direction: crate::Direction) { + self.symbol = direction.apply(self.symbol); + } +} + impl<'a, Q, S> Head<&'a Q, &'a S> { pub fn cloned(&self) -> Head where diff --git a/core/src/traits/actor.rs b/core/src/traits/actor.rs index 1de89f9..42d6d2c 100644 --- a/core/src/traits/actor.rs +++ b/core/src/traits/actor.rs @@ -2,7 +2,7 @@ Appellation: fsm Contrib: FL03 */ -use crate::Head; +use crate::{Direction, Head, State, Symbolic, Tail}; pub trait Automata { type Rule; @@ -12,27 +12,61 @@ pub trait Automata { fn current_state(&self) -> Self::State; } -pub enum Step { - Left(T), - Right(T), - Stay(T), +pub trait Store { + type Elem; + + fn get(&self, index: usize) -> &Self::Elem; + + fn set(&mut self, index: usize, symbol: Self::Elem); } -pub trait Tape { - type Symbol; +pub trait Memory { + type Elem; + + fn read(&self) -> &Self::Elem; + + fn write(&mut self, symbol: Self::Elem); +} - fn read(&self) -> Self::Symbol; +pub trait Directive { + fn direction(&self) -> crate::Direction; - fn write(&mut self, symbol: Self::Symbol); + fn state(&self) -> State<&'_ Q>; - fn step(&mut self, step: Step); + fn symbol(&self) -> &S; } -pub struct Context { +pub struct Actor { pub head: Head, - pub tape: S, + pub tape: Vec, } -pub struct Actor { - pub(crate) state: usize, - pub(crate) tape: Vec, + +impl Actor where S: Symbolic { + pub fn new(State(state): State, tape: impl IntoIterator) -> Self { + Self { + head: Head::new(State(state), 0), + tape: Vec::from_iter(tape), + } + } + + pub fn handle(&mut self, rule: D) where D: Directive { + self.write(rule.symbol().clone()); + self.head.shift_inplace(rule.direction()); + } + + pub fn len(&self) -> usize { + self.tape.len() + } + + pub fn read(&self) -> &S { + &self.tape[self.head.symbol % self.len()] + } + + pub fn write(&mut self, symbol: S) { + if self.head.symbol < self.tape.len() { + self.tape[self.head.symbol] = symbol; + } else { + self.tape.push(symbol); + } + } } \ No newline at end of file diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index 41f29db..a046dd7 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -36,11 +36,7 @@ impl TM { } } /// Creates a new instance of a [head](Head) from references to the current state and symbol; - pub fn head(&self) -> Head<&'_ Q, &'_ S> - where - Q: Clone, - S: Clone, - { + pub fn head(&self) -> Head<&'_ Q, &'_ S> { let state = self.state(); let symbol = self.tape().read().unwrap(); Head::new(state, symbol) @@ -117,10 +113,8 @@ where fn next(&mut self) -> Option { #[cfg(feature = "tracing")] tracing::info!("Stepping..."); - // Create a new head from the current state and symbol - let head = self.head().cloned(); // Get the first instruction for the current head - if let Some(&tail) = self.program.get_head(&head).first() { + if let Some(&tail) = self.program.get_head(&self.head().cloned()).first() { self.state = self.tape.update_inplace(tail.cloned()); return Some(tail.cloned().into_head()); } From 1d93e03f948583075bb87a691529eae168b7f21c Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 14:04:39 -0500 Subject: [PATCH 09/35] update Signed-off-by: Joe McCain III --- README.md | 6 +- core/src/actors/actor.rs | 50 +++++++++++++ core/src/actors/mod.rs | 39 ++++++++++ core/src/lib.rs | 6 +- core/src/ops/transform.rs | 2 +- core/src/rules/instruction.rs | 25 +++++-- core/src/rules/mod.rs | 27 ++++--- core/src/rules/parts/head.rs | 4 +- core/src/rules/program.rs | 93 +++++++++++++++++------ core/src/tape/iter.rs | 3 +- core/src/tape/mod.rs | 34 ++++----- core/src/tape/slider.rs | 47 ------------ core/src/tape/tape.rs | 44 +++++------ core/src/traits/actor.rs | 66 +--------------- core/src/types/direction.rs | 6 +- rstm/examples/basic.rs | 4 +- rstm/examples/utm.rs | 4 +- rstm/src/lib.rs | 4 +- rstm/src/sand/mod.rs | 7 -- rstm/src/sand/types/mod.rs | 16 ---- rstm/src/sand/types/registry.rs | 17 ----- rstm/src/sand/types/scope.rs | 11 --- rstm/src/sand/types/store.rs | 128 -------------------------------- rstm/src/turing.rs | 125 +++++++++++++++++++++++++++++++ rstm/src/turing/context.rs | 63 ---------------- rstm/src/turing/mod.rs | 32 -------- rstm/src/turing/model.rs | 124 ++----------------------------- 27 files changed, 386 insertions(+), 601 deletions(-) create mode 100644 core/src/actors/actor.rs create mode 100644 core/src/actors/mod.rs delete mode 100644 core/src/tape/slider.rs delete mode 100644 rstm/src/sand/mod.rs delete mode 100644 rstm/src/sand/types/mod.rs delete mode 100644 rstm/src/sand/types/registry.rs delete mode 100644 rstm/src/sand/types/scope.rs delete mode 100644 rstm/src/sand/types/store.rs create mode 100644 rstm/src/turing.rs delete mode 100644 rstm/src/turing/context.rs delete mode 100644 rstm/src/turing/mod.rs diff --git a/README.md b/README.md index 040b262..7ac538d 100644 --- a/README.md +++ b/README.md @@ -38,14 +38,14 @@ cargo build --features full -r --workspace ```rust extern crate rstm; - use rstm::{rule, Program, State, StdTape, TM}; use rstm::state::BinState::{Invalid, Valid}; + use rstm::{rule, Program, State, StdTape, TM}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); // initialize the tape data - let alpha: Vec = vec![0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; // define the rules for the machine let rules = vec![ rule![(Invalid, 0) -> Right(Invalid, 0)], @@ -55,7 +55,7 @@ cargo build --features full -r --workspace ]; let tape = StdTape::from_iter(alpha); - let program = Program::new(State(Invalid)).with_instructions(rules); + let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine let tm = TM::new(program, tape); tm.execute()?; diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs new file mode 100644 index 0000000..80a2459 --- /dev/null +++ b/core/src/actors/actor.rs @@ -0,0 +1,50 @@ +/* + Appellation: actor + Contrib: FL03 +*/ +use crate::rules::Directive; +use crate::{Head, State, Symbolic}; + +/// [Actor] aptly describe the `TMH` model +pub struct Actor { + pub head: Head, + pub tape: Vec, +} + +impl Actor { + pub fn new(State(state): State, tape: impl IntoIterator) -> Self { + Self { + head: Head::new(State(state), 0), + tape: Vec::from_iter(tape), + } + } + + pub fn handle(&mut self, rule: D) + where + D: Directive, + S: Symbolic, + { + self.write(rule.value().clone()); + self.head.shift_inplace(rule.direction()); + } + + pub fn is_halted(&self) -> bool { + self.head.symbol >= self.tape.len() + } + + pub fn len(&self) -> usize { + self.tape.len() + } + + pub fn read(&self) -> &S { + &self.tape[self.head.symbol % self.len()] + } + + pub fn write(&mut self, symbol: S) { + if self.head.symbol < self.tape.len() { + self.tape[self.head.symbol] = symbol; + } else { + self.tape.push(symbol); + } + } +} diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs new file mode 100644 index 0000000..07ab107 --- /dev/null +++ b/core/src/actors/mod.rs @@ -0,0 +1,39 @@ +/* + Appellation: actors + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::actor::Actor; + +pub(crate) mod actor; + +#[allow(unused_imports)] +pub(crate) mod prelude { + pub use super::actor::Actor; +} + +use crate::Program; + +pub struct Model { + pub actor: Actor, + pub input: Vec, + pub program: Program, +} + +impl Iterator for Model +where + Q: Clone, + S: Clone, +{ + type Item = S; + + fn next(&mut self) -> Option { + if self.actor.is_halted() { + return None; + } + + let state = self.actor.head.state.clone(); + let symbol = self.actor.read().clone(); + Some(symbol) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index b614f62..4ebda0f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -11,8 +11,8 @@ extern crate alloc; #[doc(inline)] pub use self::{ - error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::StdTape, - traits::prelude::*, types::prelude::*, + error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::Tape, traits::prelude::*, + types::prelude::*, }; #[macro_use] @@ -20,6 +20,8 @@ pub(crate) mod macros; #[macro_use] pub(crate) mod seal; +#[doc(hidden)] +pub mod actors; pub mod error; pub mod ops; pub mod rules; diff --git a/core/src/ops/transform.rs b/core/src/ops/transform.rs index c4ac584..2dea121 100644 --- a/core/src/ops/transform.rs +++ b/core/src/ops/transform.rs @@ -8,7 +8,7 @@ /// the [`map`] method, which applies a function to a value and returns a new value. pub trait Transform { type Output; - /// [`Transform::transform`] is a method that takes a reference to `self` and a value of type + /// [`Transform::transform`] is a method that takes a reference to `self` and a value of type /// `T` and returns a value of type [`Transform::Output`]. fn transform(&self, delta: T) -> Self::Output; } diff --git a/core/src/rules/instruction.rs b/core/src/rules/instruction.rs index 6f0673c..da797d7 100644 --- a/core/src/rules/instruction.rs +++ b/core/src/rules/instruction.rs @@ -17,23 +17,31 @@ impl Instruction { pub fn new() -> InstructionBuilder { InstructionBuilder::new() } - /// Returns a reference to the [head](Head) of the [instruction](Instruction) + /// Returns an immutable reference to the [Head] pub const fn head(&self) -> &Head { &self.head } - /// Returns a mutable reference to the [head](Head) of the [instruction](Instruction) + /// Returns a mutable reference to the [Head] pub fn head_mut(&mut self) -> &mut Head { &mut self.head } - /// Returns a reference to the [tail](Tail) of the [instruction](Instruction) + /// Returns an instance of the [Head] whose elements are immutable references + pub fn head_ref(&self) -> Head<&'_ Q, &'_ S> { + self.head().to_ref() + } + /// Returns an immutable reference to the [Tail] of the [Instruction] pub const fn tail(&self) -> &Tail { &self.tail } - /// Returns a mutable reference to the [tail](Tail) of the [instruction](Instruction) + /// Returns a mutable reference to the [Tail] of the [Instruction] pub fn tail_mut(&mut self) -> &mut Tail { &mut self.tail } - /// Returns the direction the [head](Head) is instructed to move + + pub fn tail_ref(&self) -> Tail<&'_ Q, &'_ S> { + self.tail().to_ref() + } + /// Returns the direction of the shift pub fn direction(&self) -> Direction { self.tail().direction() } @@ -45,11 +53,14 @@ impl Instruction { pub const fn symbol(&self) -> &S { self.head().symbol() } - /// Returns the next [state](State) the agent is instructed to move to + pub fn next_head(&self) -> Head<&'_ Q, &'_ S> { + self.tail().to_head_ref() + } + /// Returns the next [State] of the system pub fn next_state(&self) -> State<&'_ Q> { self.tail().next_state() } - /// Returns the symbol the [head](Head) is instructed to write + /// Returns the value which for which the current object will be replaced with pub const fn write_symbol(&self) -> &S { self.tail().write_symbol() } diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index deb3a0d..c191f2b 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -3,11 +3,7 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{ - instruction::*, - parts::*, - program::*, -}; +pub use self::{instruction::*, parts::*, program::*}; pub(crate) mod instruction; pub(crate) mod program; @@ -32,9 +28,18 @@ pub(crate) mod prelude { use crate::{Direction, State, Symbolic}; -pub trait Rule { +pub trait Space { type Elem; type State; + + fn state(&self) -> State<&'_ Self::State>; + + fn symbol(&self) -> &Self::Elem; +} + +pub trait Morphism { + type Input: Space; + type Output: Space; } pub trait Transition @@ -63,7 +68,7 @@ pub trait Directive { fn next_state(&self) -> State<&'_ Q>; - fn write_symbol(&self) -> &S; + fn value(&self) -> &S; } /* @@ -92,7 +97,7 @@ where } fn write_symbol(&self) -> &S { - self.write_symbol() + self.value() } } @@ -115,7 +120,7 @@ impl Directive for Instruction { self.tail().next_state() } - fn write_symbol(&self) -> &S { + fn value(&self) -> &S { &self.write_symbol() } } @@ -139,7 +144,7 @@ impl Directive for crate::Tail { self.next_state() } - fn write_symbol(&self) -> &S { + fn value(&self) -> &S { &self.write_symbol() } } @@ -163,7 +168,7 @@ impl Directive for (Direction, State, S) { self.1.to_ref() } - fn write_symbol(&self) -> &S { + fn value(&self) -> &S { &self.2 } } diff --git a/core/src/rules/parts/head.rs b/core/src/rules/parts/head.rs index 435c5f5..fd67dfa 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/rules/parts/head.rs @@ -4,7 +4,7 @@ */ use crate::state::State; -/// The head of a turing machine generally speaks to the current state and symbol of the +/// The head of a turing machine generally speaks to the current state and symbol of the /// machine w.r.t. the [tape](crate::Tape). #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -106,7 +106,7 @@ impl Head { ..self } } - + pub fn shift_inplace(&mut self, direction: crate::Direction) { self.symbol = direction.apply(self.symbol); } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index d06b390..96c2905 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -75,38 +75,89 @@ impl Program { pub fn iter(&self) -> core::slice::Iter> { self.ruleset.iter() } - /// Returns an owned reference to the element(s) specified by the index. - pub fn get(&self, idx: I) -> Option<&I::Output> + /// Returns a mutable iterator over the elements. + pub fn iter_mut(&mut self) -> core::slice::IterMut> { + self.ruleset.iter_mut() + } + /// Returns a collection of tails for a given head. + pub fn get(&self, head: &Head) -> Option<&Tail> where - I: core::slice::SliceIndex<[Instruction]>, + Q: PartialEq, + S: PartialEq, { - self.ruleset.get(idx) + self.iter().find_map(|i| { + if i.head() == head { + Some(i.tail()) + } else { + None + } + }) } - /// Returns a collection of tails for a given head. - pub fn get_head(&self, head: &Head) -> Vec> + + pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> where Q: PartialEq, S: PartialEq, { - self.iter() - .filter_map(|i| { - if i.head() == head { - Some(i.tail().to_ref()) - } else { - None - } - }) - .collect() - } - - pub fn find_head(&self, head: Head<&'_ Q, &'_ S>) -> Option<&Tail> + self.iter_mut().find_map(|i| { + if i.head() == head { + Some(i.tail_mut()) + } else { + None + } + }) + } + /// Returns a collection of tails for a given head. + pub fn get_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> where Q: PartialEq, S: PartialEq, { - self.iter() - .find(|i| i.head().to_ref() == head) - .map(|i| i.tail()) + self.iter().find_map(|i| { + if i.head_ref() == head { + Some(i.tail_ref()) + } else { + None + } + }) + } +} + +impl AsRef<[Instruction]> for Program { + fn as_ref(&self) -> &[Instruction] { + &self.ruleset + } +} + +impl AsMut<[Instruction]> for Program { + fn as_mut(&mut self) -> &mut [Instruction] { + &mut self.ruleset + } +} + +impl core::ops::Deref for Program { + type Target = [Instruction]; + + fn deref(&self) -> &Self::Target { + &self.ruleset + } +} + +impl core::ops::DerefMut for Program { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ruleset + } +} + +impl core::ops::Index> for Program +where + Q: PartialEq, + S: PartialEq, +{ + type Output = Tail; + + fn index(&self, index: Head) -> &Self::Output { + self.get(&index).unwrap() } } diff --git a/core/src/tape/iter.rs b/core/src/tape/iter.rs index 3ef9601..913a600 100644 --- a/core/src/tape/iter.rs +++ b/core/src/tape/iter.rs @@ -2,8 +2,9 @@ Appellation: iter Contrib: FL03 */ +#![allow(dead_code)] pub struct Iter<'a, T> { tape: &'a T, index: usize, -} \ No newline at end of file +} diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index deb8e85..e183d3b 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -7,7 +7,7 @@ //! Idealized Turing machines consider a tape, or memory, that is infinite in both directions. //! This tape is a one-dimensional array of symbols manipulated by the tape head according to //! some set of pre-defined rules. -pub use self::tape::StdTape; +pub use self::tape::Tape; pub(crate) mod tape; @@ -15,11 +15,9 @@ pub(crate) mod tape; pub mod entry; #[doc(hidden)] pub mod iter; -#[doc(hidden)] -pub mod slider; pub(crate) mod prelude { - pub use super::tape::StdTape; + pub use super::tape::Tape; } #[doc(hidden)] @@ -29,23 +27,21 @@ pub trait RawTape { fn as_slice(&self) -> &[Self::Elem]; } -pub trait Read { - type Elem; - - fn read(&self) -> &Self::Elem; -} - -pub trait Write { - type Elem; +/* + ************* Implementations ************* +*/ +impl RawTape for [T] { + type Elem = T; - fn write(&mut self, value: Self::Elem); + fn as_slice(&self) -> &[Self::Elem] { + &self + } } -#[doc(hidden)] -pub trait Tape: Read + Write { - fn len(&self) -> usize; +impl RawTape for Vec { + type Elem = T; - fn is_empty(&self) -> bool; + fn as_slice(&self) -> &[Self::Elem] { + &self + } } - - diff --git a/core/src/tape/slider.rs b/core/src/tape/slider.rs deleted file mode 100644 index 16a2336..0000000 --- a/core/src/tape/slider.rs +++ /dev/null @@ -1,47 +0,0 @@ -/* - Appellation: slider - Contrib: FL03 -*/ -#![allow(dead_code)] -use crate::{Head, State}; - -/// -/// -/// In the paper, ["On the topological dynamics of Turing Machines"](https://pdf.sciencedirectassets.com/271538/1-s2.0-S0304397500X00527/1-s2.0-S0304397596000254/main.pdf?X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLWVhc3QtMSJHMEUCIAs%2FIGbrXGO61g5aPm39Ib9mhu0rk0voDj%2FUKAD%2B0EmVAiEAtagmY%2FVIBX8CvMgEmXsSzaOck0zIZmmoLxZ5eicB7nwqsgUIFxAFGgwwNTkwMDM1NDY4NjUiDDYtSMTlhppTdI2XOiqPBQ0lXDEHbefl0B8yi5yFePwQGNd18aDmyxP8Gglg%2FY5BIAPdXUNRIoe50cEbiKFm8HdtxVoszJGOBqN71165Tulos2iAdYmhGkzcqMJMikG%2FpAfZu1x3uo3frEbNtIW2J%2FSYo0vrK2OXh3LXb4VQkoZpceVDrG26ZgZWIuUXuSomzBkxy%2BfqvaOeqNrKqN22mxQe59mJYQCgaDP0ev1zltb8ULFHKHv35%2FX98bXTIXXBp7IXMjHdXddO9jhHONGa6HbGazEBhpxy1xs3mADH1ErJ0JlWG0GZwrkz9VM9ap%2Bwnq9niYgYd1adWqeuep6POgA0SZtgAFFFGLtGeHTRx%2B8I%2BSSzzYXK4rrNjnsdJXMkK9fXPOsTZPbtafM5IVBCtCFIClrRx9AKe%2FpDGNGJ9um2Teh%2FgZdamXl0dLCHBmUxxXXf5cH7QBPV1YzOO%2FdsFxhvrST%2FW7BWDEeNV89UVAjJjRXD4gT64B1aujgX55UCgYRJKpi8r8Z7scMdywDUA8lTFxG8ckFy8VSJXP4XIUo76TdmRao2MiDo6a0S3QUvlXp9j01mB%2FLRF0%2Bj7HPOH6PI23YdvMI1U%2BnwYu9FgyfFt8gDO6a3JYDUYmco5K13YXn0BiJtO4bd8D9q2WyCYoHzog4fDPKLArmrEqbBXqcJ5E6SEz7OkQuVIm3eFmSMsU%2BmbXx8di%2FRWaCVpwht3okeVnsci%2F2IMBwCiZnoByJ9a3KD9xavV81n6h%2BAL8YD2tyR%2BqaZdgi%2Fx8eMS8H14cLJB6o8ZpiGmthUXT66emKAhZfhnTweLEuEavsZcMIMOuI%2B9FEC2dfeUWjdtm0VnrufqEID2%2BowOXodj65RLAiD2wKTLYyuVVApBRW%2FFw0wrp%2BZtQY6sQEvfJW%2BnFXtKiHbJusaao0u5Y3T6RDPxNbcZMt1A%2FkN6icm1%2BP32LwAQ2DLIxmT6SFpc1SxogGCfvggZtF%2BxERxIr9B3HpMNnfvvEh9NvD6NQQAqbINxzEoKIMXksRuc5wrnry1KmA51CtmfJ2TbJOlZ1KWI%2FIJW1gcoU0omdhntl3162JQQZFd9jIKQ07K2ojI8FXtcs3tAJQho5g4eM%2F7bCqvDb1Sgn0B77vPL8LEdKI%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240728T144819Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=ASIAQ3PHCVTY2B4ENHUE%2F20240728%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=35f40e1e6e1411dc3690307138e19043edef6f667f5ac5bbf191e0178217abc5&hash=0864d2d44896ab80e9b8766f9dd8b8d7516f124c8f19c29db323f504115bb2ba&host=68042c943591013ac2b2430a89b270f6af2c76d8dfd086a07176afe7c76c2c61&pii=S0304397596000254&tid=spdf-68cb7082-4608-4105-848d-6c23a206e008&sid=920ea93d24f32844d618d475ca675f16e0cbgxrqa&type=client&tsoh=d3d3LnNjaWVuY2VkaXJlY3QuY29t&ua=17155c0606530e0553&rr=8aa5ab6279d016b8&cc=us) -/// the authors define the state of a Turing machine to be its configuration. This -/// configuration consists of the inner state of the head, the symbol it is reading, -/// and the contents of the tape. -pub struct Slider { - pub(crate) head: Head, // head of the tape - /// state of the machine - pub(crate) tape: Vec, -} - -impl Slider { - pub fn new(State(state): State, tape: impl IntoIterator) -> Self { - Self { - head: Head::new(State(state), 0), - tape: tape.into_iter().collect(), - } - } - /// Returns an immutable reference to the head of the machine. - pub fn head(&self) -> &Head { - &self.head - } - /// Returns the current state of the machine. - pub fn state(&self) -> State<&Q> { - self.head.state.to_ref() - } - /// Returns the current position of the head on the tape. - pub fn pos(&self) -> usize { - self.head.symbol - } - /// Returns the current symbol being read by the head. - pub fn read(&self) -> &S { - &self.tape[self.pos()] - } - /// Writes a symbol to the tape at the current position of the head. - pub fn write(&mut self, symbol: S) { - self.tape[self.head.symbol] = symbol; - } -} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index c412a57..ad03638 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -20,18 +20,18 @@ use core::cell::Cell; /// be [Direction::Stay]. Moving left and right within a linear space speaks directly /// to a translation or shift in space, however, staying in place does not result in /// any movement, shift, or translation within space. That being said, staying still -/// is an operation that does result in some change in-time. +/// is an operation that does result in some change in-time. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct StdTape { +pub struct Tape { cursor: usize, store: Vec, ticks: Cell, } -impl StdTape { +impl Tape { pub fn new() -> Self { - StdTape { + Tape { cursor: 0, store: Vec::::new(), ticks: Cell::default(), @@ -39,7 +39,7 @@ impl StdTape { } /// Constructs a new tape from an iterator. pub fn from_iter(iter: impl IntoIterator) -> Self { - StdTape { + Tape { cursor: 0, store: Vec::from_iter(iter), ticks: Cell::default(), @@ -47,7 +47,7 @@ impl StdTape { } /// Constructs a new, empty tape with the specified capacity. pub fn with_capacity(capacity: usize) -> Self { - StdTape { + Tape { cursor: 0, store: Vec::::with_capacity(capacity), ticks: Cell::default(), @@ -175,9 +175,9 @@ impl StdTape { } } -impl StdTape { - pub fn from_str(input: &str) -> StdTape { - StdTape { +impl Tape { + pub fn from_str(input: &str) -> Tape { + Tape { cursor: 0, store: input.chars().collect(), ticks: Cell::default(), @@ -185,31 +185,31 @@ impl StdTape { } } -impl AsRef<[S]> for StdTape { +impl AsRef<[S]> for Tape { fn as_ref(&self) -> &[S] { &self.store } } -impl AsMut<[S]> for StdTape { +impl AsMut<[S]> for Tape { fn as_mut(&mut self) -> &mut [S] { &mut self.store } } -impl core::borrow::Borrow<[S]> for StdTape { +impl core::borrow::Borrow<[S]> for Tape { fn borrow(&self) -> &[S] { &self.store } } -impl core::borrow::BorrowMut<[S]> for StdTape { +impl core::borrow::BorrowMut<[S]> for Tape { fn borrow_mut(&mut self) -> &mut [S] { &mut self.store } } -impl core::ops::Deref for StdTape { +impl core::ops::Deref for Tape { type Target = [S]; fn deref(&self) -> &Self::Target { @@ -217,13 +217,13 @@ impl core::ops::Deref for StdTape { } } -impl core::ops::DerefMut for StdTape { +impl core::ops::DerefMut for Tape { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.store } } -impl core::fmt::Display for StdTape +impl core::fmt::Display for Tape where S: core::fmt::Display, { @@ -238,7 +238,7 @@ where } } -impl core::iter::Extend for StdTape { +impl core::iter::Extend for Tape { fn extend(&mut self, iter: T) where T: IntoIterator, @@ -247,16 +247,16 @@ impl core::iter::Extend for StdTape { } } -impl core::iter::FromIterator for StdTape { +impl core::iter::FromIterator for Tape { fn from_iter(iter: I) -> Self where I: IntoIterator, { - StdTape::from_iter(iter) + Tape::from_iter(iter) } } -impl core::iter::IntoIterator for StdTape { +impl core::iter::IntoIterator for Tape { type Item = S; type IntoIter = std::vec::IntoIter; @@ -265,7 +265,7 @@ impl core::iter::IntoIterator for StdTape { } } -impl core::ops::Index for StdTape +impl core::ops::Index for Tape where I: core::slice::SliceIndex<[S]>, { @@ -276,7 +276,7 @@ where } } -impl core::ops::IndexMut for StdTape +impl core::ops::IndexMut for Tape where I: core::slice::SliceIndex<[S]>, { diff --git a/core/src/traits/actor.rs b/core/src/traits/actor.rs index 42d6d2c..d127e0a 100644 --- a/core/src/traits/actor.rs +++ b/core/src/traits/actor.rs @@ -2,71 +2,9 @@ Appellation: fsm Contrib: FL03 */ -use crate::{Direction, Head, State, Symbolic, Tail}; -pub trait Automata { - type Rule; - type State; - type Symbol; - - fn current_state(&self) -> Self::State; -} - -pub trait Store { - type Elem; - - fn get(&self, index: usize) -> &Self::Elem; - - fn set(&mut self, index: usize, symbol: Self::Elem); -} - -pub trait Memory { +pub trait RawSpace { type Elem; - fn read(&self) -> &Self::Elem; - - fn write(&mut self, symbol: Self::Elem); -} - -pub trait Directive { - fn direction(&self) -> crate::Direction; - - fn state(&self) -> State<&'_ Q>; - - fn symbol(&self) -> &S; -} - -pub struct Actor { - pub head: Head, - pub tape: Vec, + fn space(&self) -> Self::Elem; } - -impl Actor where S: Symbolic { - pub fn new(State(state): State, tape: impl IntoIterator) -> Self { - Self { - head: Head::new(State(state), 0), - tape: Vec::from_iter(tape), - } - } - - pub fn handle(&mut self, rule: D) where D: Directive { - self.write(rule.symbol().clone()); - self.head.shift_inplace(rule.direction()); - } - - pub fn len(&self) -> usize { - self.tape.len() - } - - pub fn read(&self) -> &S { - &self.tape[self.head.symbol % self.len()] - } - - pub fn write(&mut self, symbol: S) { - if self.head.symbol < self.tape.len() { - self.tape[self.head.symbol] = symbol; - } else { - self.tape.push(symbol); - } - } -} \ No newline at end of file diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 9cc4238..8b954df 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -95,7 +95,7 @@ impl Direction { _ => Self::Stay, } } - /// Converts a [char] value into a direction; matches the value to the corresponding + /// Converts a [char] value into a direction; matches the value to the corresponding /// [direction](Direction). pub fn from_char(value: char) -> Self { match value { @@ -120,8 +120,8 @@ impl Direction { Self::Stay => 'S', } } - /// Applies the shift to the given position in the [direction](Direction) specified by the - /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) + /// Applies the shift to the given position in the [direction](Direction) specified by the + /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) /// method. pub fn apply(self, cur: usize) -> usize { cur.wrapping_add_signed(self as isize) diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 00b2fc5..f62a6a1 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -5,7 +5,7 @@ extern crate rstm; use rstm::state::BinState::{Invalid, Valid}; -use rstm::{rule, Program, State, StdTape, TM}; +use rstm::{rule, Program, State, Tape, TM}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); @@ -20,7 +20,7 @@ fn main() -> Result<(), Box> { rule![(Valid, 1) -> Left(Valid, 0)], ]; - let tape = StdTape::from_iter(alpha); + let tape = Tape::from_iter(alpha); let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine let tm = TM::new(program, tape); diff --git a/rstm/examples/utm.rs b/rstm/examples/utm.rs index 76f4d51..9083282 100644 --- a/rstm/examples/utm.rs +++ b/rstm/examples/utm.rs @@ -4,8 +4,8 @@ */ extern crate rstm; -use rstm::{rule, Program, State, StdTape, TM}; use rstm::state::BinState::{Invalid, Valid}; +use rstm::{rule, Program, State, Tape, TM}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); @@ -20,7 +20,7 @@ fn main() -> Result<(), Box> { rule![(Valid, 1) -> Left(Valid, 0)], ]; - let tape = StdTape::from_iter(alpha); + let tape = Tape::from_iter(alpha); let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine let tm = TM::new(program, tape); diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index aa74352..9266585 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -20,11 +20,9 @@ pub(crate) mod macros { pub mod rules; } -#[doc(hidden)] -pub mod sand; pub mod turing; pub mod prelude { - pub use crate::turing::prelude::*; + pub use crate::turing::TM; pub use rstm_core::prelude::*; } diff --git a/rstm/src/sand/mod.rs b/rstm/src/sand/mod.rs deleted file mode 100644 index f224617..0000000 --- a/rstm/src/sand/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -/* - Appellation: sand - Contrib: FL03 -*/ -#![allow(unused)] - -pub mod types; diff --git a/rstm/src/sand/types/mod.rs b/rstm/src/sand/types/mod.rs deleted file mode 100644 index 2134f89..0000000 --- a/rstm/src/sand/types/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -/* - Appellation: types - Contrib: FL03 -*/ - -pub mod registry; -pub mod scope; -pub mod store; - -pub(crate) mod prelude { - - pub(crate) use super::Idx; -} - -/// A type alias generally used to represent the position of a value within a collection. -pub(crate) type Idx = usize; diff --git a/rstm/src/sand/types/registry.rs b/rstm/src/sand/types/registry.rs deleted file mode 100644 index fdc83e0..0000000 --- a/rstm/src/sand/types/registry.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - Appellation: registry - Contrib: FL03 -*/ -use crate::rules::Instruction; -use std::collections::hash_map::{self, HashMap}; - -type Store = HashMap>; - -pub struct Registry { - pub(crate) rules: HashMap>, -} - -pub struct Actor { - pub(crate) pos: isize, // - pub(crate) rule: Instruction, -} diff --git a/rstm/src/sand/types/scope.rs b/rstm/src/sand/types/scope.rs deleted file mode 100644 index b245e3f..0000000 --- a/rstm/src/sand/types/scope.rs +++ /dev/null @@ -1,11 +0,0 @@ -/* - Appellation: agent - Contrib: FL03 -*/ - -use crate::state::State; - -pub struct Observer { - pub position: usize, - pub state: State, -} diff --git a/rstm/src/sand/types/store.rs b/rstm/src/sand/types/store.rs deleted file mode 100644 index b1eea15..0000000 --- a/rstm/src/sand/types/store.rs +++ /dev/null @@ -1,128 +0,0 @@ -/* - Appellation: symbol - Contrib: FL03 -*/ -use crate::{Head, Symbolic, Tail}; -use std::collections::hash_map::{self, Entry, HashMap}; - -pub struct Ruleset { - pub(crate) rules: HashMap, Tail>, -} - -impl Ruleset -where - Q: Eq + core::hash::Hash, - S: Symbolic, -{ - pub fn new() -> Self { - Ruleset { - rules: HashMap::new(), - } - } - pub fn from_iter(iter: I) -> Self - where - I: IntoIterator, - R: Into<(Head, Tail)>, - HashMap, Tail>: FromIterator, - { - Ruleset { - rules: iter.into_iter().collect(), - } - } - pub fn from_rules(rules: HashMap, Tail>) -> Self { - Ruleset { rules } - } - /// Given a head, returns an [entry](Entry) in the ruleset for in-place manipulation - pub fn entry(&mut self, key: Head) -> Entry<'_, Head, Tail> { - self.rules.entry(key) - } - /// Inserts a new rule into the ruleset - pub fn insert(&mut self, head: Head, tail: Tail) { - self.rules.insert(head, tail); - } - /// Returns a reference to the tail of a given head; - /// if the head is not in the ruleset, returns [None](Option::None) - pub fn get(&self, head: &Head) -> Option<&Tail> { - self.rules.get(head) - } - /// Returns a mutable reference to the tail of a given head; - /// if the head is not in the ruleset, returns [None](Option::None) - pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> { - self.rules.get_mut(head) - } - /// Returns the number of rules in the ruleset - pub fn len(&self) -> usize { - self.rules.len() - } - /// Check to see whether the ruleset is empty - pub fn is_empty(&self) -> bool { - self.rules.is_empty() - } - - pub fn iter(&self) -> hash_map::Iter<'_, Head, Tail> { - self.rules.iter() - } - - pub fn iter_mut(&mut self) -> hash_map::IterMut<'_, Head, Tail> { - self.rules.iter_mut() - } - - pub fn keys(&self) -> hash_map::Keys<'_, Head, Tail> { - self.rules.keys() - } - - pub fn values(&self) -> hash_map::Values<'_, Head, Tail> { - self.rules.values() - } - - pub fn values_mut(&mut self) -> hash_map::ValuesMut<'_, Head, Tail> { - self.rules.values_mut() - } - - pub fn retain(&mut self, f: F) - where - F: FnMut(&Head, &mut Tail) -> bool, - { - self.rules.retain(f) - } - - pub fn remove(&mut self, head: &Head) -> Option> { - self.rules.remove(head) - } -} - -impl Extend<(Head, Tail)> for Ruleset -where - Q: Eq + core::hash::Hash, - S: Symbolic, -{ - fn extend(&mut self, iter: T) - where - T: IntoIterator, Tail)>, - { - self.rules.extend(iter) - } -} - -impl Extend> for Ruleset -where - Q: Eq + core::hash::Hash, - S: Symbolic, -{ - fn extend(&mut self, iter: T) - where - T: IntoIterator>, - { - self.rules - .extend(iter.into_iter().map(|i| (i.head, i.tail))) - } -} - -impl IntoIterator for Ruleset { - type Item = (Head, Tail); - type IntoIter = hash_map::IntoIter, Tail>; - - fn into_iter(self) -> Self::IntoIter { - self.rules.into_iter() - } -} diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs new file mode 100644 index 0000000..c43233f --- /dev/null +++ b/rstm/src/turing.rs @@ -0,0 +1,125 @@ +/* + Appellation: tm + Contrib: FL03 +*/ +pub use self::model::Turing; + +pub(crate) mod model; + +use crate::prelude::{Error, Head, Symbolic, Tape}; +use crate::rules::Program; +use crate::state::State; + +/// # Turing Machine ([TM]) +/// +/// The Turing Machine is a mathematical model of computation that uses a set of rules to determine +/// how a machine should manipulate a tape. The machine can read, write, and move linearly across the tape. +/// Each pre-defined rule maps a head, consisting of a state and symbol, to a new state and symbol along with a direction. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct TM { + pub(crate) program: Program, + pub(crate) state: State, + pub(crate) tape: Tape, +} + +impl TM { + pub fn new(program: Program, tape: Tape) -> Self + where + Q: Clone + Default, + S: Default, + { + let state = program.initial_state().cloned(); + TM { + program, + state, + tape, + } + } + /// Returns an immutable reference to the [program](Program) + pub const fn program(&self) -> &Program { + &self.program + } + /// Creates a new instance of a [head](Head) from references to the current state and symbol; + pub fn read(&self) -> Option> { + self.tape() + .read() + .ok() + .map(|symbol| Head::new(self.state(), symbol)) + } + /// Returns an instance of the [state](State) with an immutable + /// reference to the internal data + pub fn state(&self) -> State<&'_ Q> { + self.state.to_ref() + } + /// Returns an instance of the [state](State) with a mutable + /// reference to the internal data + pub fn state_mut(&mut self) -> State<&'_ mut Q> { + self.state.to_mut() + } + /// Returns an instance of the [state](State) with an immutable + pub fn set_state(&mut self, state: State) { + self.state = state; + } + /// Returns an immutable reference to the [tape](StdTape) + pub const fn tape(&self) -> &Tape { + &self.tape + } + /// Returns a mutable reference to the [tape](StdTape) + pub fn tape_mut(&mut self) -> &mut Tape { + &mut self.tape + } + /// Runs the program until the + /// + /// The program will continue to run until the current state is a halt state. + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "run", target = "fsm") + )] + pub fn execute(mut self) -> Result<(), Error> + where + Q: Clone + PartialEq, + S: Symbolic, + { + #[cfg(feature = "tracing")] + tracing::info!("Running the program..."); + loop { + #[cfg(feature = "tracing")] + tracing::info!("{}", &self.tape); + match self.next() { + Some(_) => { + // if self.current_state().is_halt() { + // return Ok(()); + // } + continue; + } + None => { + return Err(Error::unknown("Runtime Error")); + } + } + } + } +} + +impl core::iter::Iterator for TM +where + Q: Clone + PartialEq, + S: Symbolic, +{ + type Item = Head; + + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "fsm") + )] + fn next(&mut self) -> Option { + #[cfg(feature = "tracing")] + tracing::info!("Stepping..."); + // Get the first instruction for the current head + if let Some(tail) = self.program.get_ref(self.read()?) { + self.state = self.tape.update_inplace(tail.cloned()); + return Some(tail.cloned().into_head()); + } + None + } +} diff --git a/rstm/src/turing/context.rs b/rstm/src/turing/context.rs deleted file mode 100644 index 018b949..0000000 --- a/rstm/src/turing/context.rs +++ /dev/null @@ -1,63 +0,0 @@ -/* - 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<&'_ Q> { - // let q = &self.state.map(State::into_inner).unwrap_or(self.program.initial_state.into_inner()); - // State(q) - // } - - pub fn initial_state(&self) -> State<&'_ Q> { - 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/mod.rs b/rstm/src/turing/mod.rs deleted file mode 100644 index c9b33e9..0000000 --- a/rstm/src/turing/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - Appellation: turing - Contrib: FL03 -*/ -//! # Turing Machine ([TM]) -//! -//! ### 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::{context::Context, model::TM}; - -pub(crate) mod context; -pub(crate) mod model; - -pub(crate) mod prelude { - pub use super::model::TM; -} - -use crate::prelude::Alphabet; - -#[doc(hidden)] -pub trait Turing { - type Alpha: Alphabet; // input alphabet - type Beta: Alphabet; // output alphabet - - - fn step(&self, input: Self::Alpha) -> Self::Beta; -} diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index a046dd7..2c78865 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -1,123 +1,13 @@ /* - Appellation: tm + Appellation: model Contrib: FL03 */ -use crate::prelude::{Error, Head, StdTape, Symbolic}; -use crate::rules::Program; -use crate::state::State; +use crate::Alphabet; -/// # Turing Machine ([TM]) -/// -/// The Turing Machine is a mathematical model of computation that uses a set of rules to determine -/// how a machine should manipulate a tape. The machine can read, write, and move linearly across the tape. -/// Each pre-defined rule maps a head, consisting of a state and symbol, to a new state and symbol along with a direction. -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct TM { - pub(crate) program: Program, - pub(crate) state: State, - pub(crate) tape: StdTape, -} - -impl TM { - pub fn new( - program: Program, - tape: StdTape, - ) -> Self - where - Q: Clone + Default, - S: Default, - { - let state = program.initial_state().cloned(); - TM { - program, - state, - tape, - } - } - /// Creates a new instance of a [head](Head) from references to the current state and symbol; - pub fn head(&self) -> Head<&'_ Q, &'_ S> { - let state = self.state(); - let symbol = self.tape().read().unwrap(); - Head::new(state, symbol) - } - /// Returns an immutable reference to the [program](Program) - pub const fn program(&self) -> &Program { - &self.program - } - /// Returns an instance of the [state](State) with an immutable - /// reference to the internal data - pub fn state(&self) -> State<&'_ Q> { - self.state.to_ref() - } - /// Returns an instance of the [state](State) with a mutable - /// reference to the internal data - pub fn state_mut(&mut self) -> State<&'_ mut Q> { - self.state.to_mut() - } - /// Returns an instance of the [state](State) with an immutable - pub fn set_state(&mut self, state: State) { - self.state = state; - } - /// Returns an immutable reference to the [tape](StdTape) - pub const fn tape(&self) -> &StdTape { - &self.tape - } - /// Returns a mutable reference to the [tape](StdTape) - pub fn tape_mut(&mut self) -> &mut StdTape { - &mut self.tape - } - /// Runs the program until the - /// - /// The program will continue to run until the current state is a halt state. - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "run", target = "fsm") - )] - pub fn execute(mut self) -> Result<(), Error> - where - Q: Clone + PartialEq, - S: Symbolic, - { - #[cfg(feature = "tracing")] - tracing::info!("Running the program..."); - loop { - #[cfg(feature = "tracing")] - tracing::info!("{}", &self.tape); - match self.next() { - Some(_) => { - // if self.current_state().is_halt() { - // return Ok(()); - // } - continue; - } - None => { - return Err(Error::unknown("Runtime Error")); - } - } - } - } -} - -impl core::iter::Iterator for TM -where - Q: Clone + PartialEq, - S: Symbolic, -{ - type Item = Head; +#[doc(hidden)] +pub trait Turing { + type Alpha: Alphabet; // input alphabet + type Beta: Alphabet; // output alphabet - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "fsm") - )] - fn next(&mut self) -> Option { - #[cfg(feature = "tracing")] - tracing::info!("Stepping..."); - // Get the first instruction for the current head - if let Some(&tail) = self.program.get_head(&self.head().cloned()).first() { - self.state = self.tape.update_inplace(tail.cloned()); - return Some(tail.cloned().into_head()); - } - None - } + fn step(&self, input: Self::Alpha) -> Self::Beta; } From 6d9011c4bbbadd8a70dd24c403f5cb10d958798d Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Mon, 29 Jul 2024 15:30:47 -0500 Subject: [PATCH 10/35] update Signed-off-by: Joe McCain III --- core/src/state/state.rs | 7 ++++--- core/src/state/states/halting.rs | 16 +++++++++------- rstm/src/turing.rs | 21 ++++++++++++--------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 66977b5..63fd175 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -93,6 +93,9 @@ impl State { { core::any::TypeId::of::() } + pub fn is_halt(&self) -> bool where Q: 'static { + core::any::TypeId::of::() == core::any::TypeId::of::>>() + } } impl State> { @@ -100,9 +103,7 @@ impl State> { pub fn halt(Halt(inner): Halt) -> Self { Self(Halt(inner)) } - pub fn is_halt(&self) -> bool { - true - } + } impl<'a, Q> State<&'a Q> { diff --git a/core/src/state/states/halting.rs b/core/src/state/states/halting.rs index 537a3bd..f2def94 100644 --- a/core/src/state/states/halting.rs +++ b/core/src/state/states/halting.rs @@ -5,17 +5,14 @@ use crate::state::State; #[doc(hidden)] -pub trait Halter { +pub trait Halting { const HALT: bool = true; private!(); -} -#[doc(hidden)] -pub enum Halting { - Continue(T), - Halt(T), + } + pub struct Halt(pub T); impl Halt { @@ -31,8 +28,13 @@ impl Halt { pub fn as_mut(&mut self) -> &mut T { &mut self.0 } + +} + +impl Halting for Halt { + seal!(); } -impl Halter for State> { +impl Halting for State> { seal!(); } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index c43233f..9b16158 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -78,7 +78,7 @@ impl TM { )] pub fn execute(mut self) -> Result<(), Error> where - Q: Clone + PartialEq, + Q: Clone + PartialEq + 'static, S: Symbolic, { #[cfg(feature = "tracing")] @@ -87,12 +87,12 @@ impl TM { #[cfg(feature = "tracing")] tracing::info!("{}", &self.tape); match self.next() { - Some(_) => { - // if self.current_state().is_halt() { - // return Ok(()); - // } - continue; - } + Some(_) => if self.state.is_halt() { + return Ok(()); + } else { + continue; + }, + None => { return Err(Error::unknown("Runtime Error")); } @@ -103,7 +103,7 @@ impl TM { impl core::iter::Iterator for TM where - Q: Clone + PartialEq, + Q: Clone + PartialEq + 'static, S: Symbolic, { type Item = Head; @@ -115,11 +115,14 @@ where fn next(&mut self) -> Option { #[cfg(feature = "tracing")] tracing::info!("Stepping..."); + if self.state.is_halt() { + return None; + } // Get the first instruction for the current head if let Some(tail) = self.program.get_ref(self.read()?) { self.state = self.tape.update_inplace(tail.cloned()); return Some(tail.cloned().into_head()); } - None + unreachable!("No instruction found for the current head") } } From f0ae965a0b526f2166cddff8bd9e2cd3923151c3 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 30 Jul 2024 10:50:51 -0500 Subject: [PATCH 11/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 10 ++++++++- core/src/actors/mod.rs | 23 ++++++++++++--------- core/src/macros.rs | 3 +++ core/src/macros/fmt.rs | 18 +++++++++++++++++ core/src/rules/program.rs | 21 +++++++++++++++---- core/src/state/mod.rs | 9 ++++++--- core/src/state/state.rs | 14 ++++++++----- core/src/state/transition.rs | 9 --------- rstm/src/turing.rs | 39 +++++++++++++++++++++++++++--------- rstm/src/turing/model.rs | 2 +- 10 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 core/src/macros/fmt.rs delete mode 100644 core/src/state/transition.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 80a2459..9b3c507 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -19,13 +19,21 @@ impl Actor { } } - pub fn handle(&mut self, rule: D) + pub fn state(&self) -> State<&Q> { + self.head.state.to_ref() + } + + pub fn handle(&mut self, rule: D) -> Head<&Q, &S> where D: Directive, S: Symbolic, { self.write(rule.value().clone()); self.head.shift_inplace(rule.direction()); + Head { + state: self.head.state.to_ref(), + symbol: self.read(), + } } pub fn is_halted(&self) -> bool { diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 07ab107..9a75760 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -12,18 +12,22 @@ pub(crate) mod prelude { pub use super::actor::Actor; } -use crate::Program; +use crate::{Program, Symbolic}; pub struct Model { pub actor: Actor, - pub input: Vec, - pub program: Program, + pub program: Program, } +impl Model { + pub fn with_program(self, program: Program) -> Self { + Model { program, ..self } + } +} impl Iterator for Model where - Q: Clone, - S: Clone, + Q: Clone + PartialEq, + S: Symbolic, { type Item = S; @@ -31,9 +35,10 @@ where if self.actor.is_halted() { return None; } - - let state = self.actor.head.state.clone(); - let symbol = self.actor.read().clone(); - Some(symbol) + let state = self.actor.state(); + let symbol = self.actor.read(); + let rule = self.program.get(state, symbol)?; + self.actor.handle(rule.clone()); + unimplemented!() } } diff --git a/core/src/macros.rs b/core/src/macros.rs index 97f981e..b5dcaa0 100644 --- a/core/src/macros.rs +++ b/core/src/macros.rs @@ -2,6 +2,9 @@ Appellation: macros Contrib: FL03 */ +#![allow(unused)] +#[macro_use] +pub mod fmt; #[macro_use] pub mod states; diff --git a/core/src/macros/fmt.rs b/core/src/macros/fmt.rs new file mode 100644 index 0000000..82c1ac8 --- /dev/null +++ b/core/src/macros/fmt.rs @@ -0,0 +1,18 @@ +/* + Appellation: fmt + Contrib: FL03 +*/ + +macro_rules! unit_impl_fmt { + (@impl $trait:ident::<$T:ty>($($fmt:tt)*)) => { + impl core::fmt::$trait for $T { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::$trait::fmt(self, f, $($fmt)*) + } + } + }; + ($T:ty: $($trait:ident($($fmt:tt)*)),*) => { + $(impl_fmt!(@impl $trait::<$T>($($fmt)*));)* + }; +} + diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 96c2905..9871772 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -79,8 +79,21 @@ impl Program { pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.ruleset.iter_mut() } + pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> + where + Q: PartialEq, + S: PartialEq, + { + self.iter().find_map(|i| { + if i.head_ref() == Head::new(State(state), symbol) { + Some(i.tail()) + } else { + None + } + }) + } /// Returns a collection of tails for a given head. - pub fn get(&self, head: &Head) -> Option<&Tail> + pub fn get_head(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq, @@ -94,7 +107,7 @@ impl Program { }) } - pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> + pub fn get_head_mut(&mut self, head: &Head) -> Option<&mut Tail> where Q: PartialEq, S: PartialEq, @@ -108,7 +121,7 @@ impl Program { }) } /// Returns a collection of tails for a given head. - pub fn get_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> + pub fn get_head_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> where Q: PartialEq, S: PartialEq, @@ -157,7 +170,7 @@ where type Output = Tail; fn index(&self, index: Head) -> &Self::Output { - self.get(&index).unwrap() + self.get_head(&index).unwrap() } } diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index c6e407d..e0435af 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -21,20 +21,23 @@ pub(crate) mod prelude { pub use super::states::*; } +pub type AnyState = State>; + #[doc(hidden)] -pub trait RawState { +pub trait StateData { type Data; } #[doc(hidden)] pub trait Stateful { - type State: RawState; + type State: StateData; } + /* ************* Implementations ************* */ -impl RawState for State { +impl StateData for State { type Data = Q; } diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 63fd175..058c807 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -22,11 +22,15 @@ impl State { pub fn as_mut(&mut self) -> &mut Q { &mut self.0 } + /// Consumes the state and returns a boxed state. + pub fn boxed(self) -> State> { + State(Box::new(self.0)) + } /// Consumes and returns the inner value of the [state](State). pub fn into_inner(self) -> Q { self.0 } - + /// Consumes the state and returns an owned state. pub fn into_owned(self) -> State where Q: Clone, @@ -199,18 +203,18 @@ 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 +impl PartialEq for State where - Q: core::cmp::PartialEq, + Q: PartialEq, { fn eq(&self, other: &Q) -> bool { self.0 == *other } } -impl core::cmp::PartialOrd for State +impl PartialOrd for State where - Q: core::cmp::PartialOrd, + Q: PartialOrd, { fn partial_cmp(&self, other: &Q) -> Option { self.0.partial_cmp(other) diff --git a/core/src/state/transition.rs b/core/src/state/transition.rs deleted file mode 100644 index a43e9e0..0000000 --- a/core/src/state/transition.rs +++ /dev/null @@ -1,9 +0,0 @@ -/* - Appellation: transition - Contrib: FL03 -*/ - -pub struct Entry { - key: Head, - value: Tail, -} \ No newline at end of file diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 9b16158..270297b 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -57,10 +57,6 @@ impl TM { pub fn state_mut(&mut self) -> State<&'_ mut Q> { self.state.to_mut() } - /// Returns an instance of the [state](State) with an immutable - pub fn set_state(&mut self, state: State) { - self.state = state; - } /// Returns an immutable reference to the [tape](StdTape) pub const fn tape(&self) -> &Tape { &self.tape @@ -74,7 +70,7 @@ impl TM { /// The program will continue to run until the current state is a halt state. #[cfg_attr( feature = "tracing", - tracing::instrument(skip_all, name = "run", target = "fsm") + tracing::instrument(skip_all, name = "run", target = "turing") )] pub fn execute(mut self) -> Result<(), Error> where @@ -87,18 +83,41 @@ impl TM { #[cfg(feature = "tracing")] tracing::info!("{}", &self.tape); match self.next() { - Some(_) => if self.state.is_halt() { + Some(_) => { + if self.state.is_halt() { return Ok(()); } else { continue; - }, - + } + } None => { return Err(Error::unknown("Runtime Error")); } } } } + + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "turing") + )] + fn process(&mut self) -> Option> + where + Q: Clone + PartialEq + 'static, + S: Clone + PartialEq, + { + #[cfg(feature = "tracing")] + tracing::info!("Stepping..."); + if self.state.is_halt() { + return None; + } + // Get the first instruction for the current head + if let Some(tail) = self.program.get_head_ref(self.read()?) { + self.state = self.tape.update_inplace(tail.cloned()); + return Some(tail.cloned().into_head()); + } + unreachable!("No instruction found for the current head") + } } impl core::iter::Iterator for TM @@ -110,7 +129,7 @@ where #[cfg_attr( feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "fsm") + tracing::instrument(skip_all, name = "step", target = "turing") )] fn next(&mut self) -> Option { #[cfg(feature = "tracing")] @@ -119,7 +138,7 @@ where return None; } // Get the first instruction for the current head - if let Some(tail) = self.program.get_ref(self.read()?) { + if let Some(tail) = self.program.get_head_ref(self.read()?) { self.state = self.tape.update_inplace(tail.cloned()); return Some(tail.cloned().into_head()); } diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs index 2c78865..7b62e86 100644 --- a/rstm/src/turing/model.rs +++ b/rstm/src/turing/model.rs @@ -9,5 +9,5 @@ pub trait Turing { type Alpha: Alphabet; // input alphabet type Beta: Alphabet; // output alphabet - fn step(&self, input: Self::Alpha) -> Self::Beta; + fn step(&mut self, input: Self::Alpha) -> Self::Beta; } From 620ea5287050b96201f2a96e1e9afd8b8e1d4b53 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Tue, 30 Jul 2024 11:56:55 -0500 Subject: [PATCH 12/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 37 +++++++++++++++++++++----------- core/src/rules/instruction.rs | 2 +- core/src/rules/mod.rs | 2 +- core/src/rules/parts/head.rs | 10 +++------ core/src/rules/program.rs | 1 + core/src/state/mod.rs | 11 +++++----- core/src/state/states/halting.rs | 9 +++++++- core/src/traits/symbolic.rs | 17 +++++++-------- rstm/src/turing.rs | 24 +++++---------------- 9 files changed, 57 insertions(+), 56 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 9b3c507..632beb1 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -7,20 +7,27 @@ use crate::{Head, State, Symbolic}; /// [Actor] aptly describe the `TMH` model pub struct Actor { - pub head: Head, - pub tape: Vec, + /// the input alphabet + pub alpha: Vec, + pub ptr: Head, } impl Actor { pub fn new(State(state): State, tape: impl IntoIterator) -> Self { Self { - head: Head::new(State(state), 0), - tape: Vec::from_iter(tape), + alpha: Vec::from_iter(tape), + ptr: Head::new(State(state), 0), } } + pub const fn head(&self) -> &Head { + &self.ptr + } + + + pub fn state(&self) -> State<&Q> { - self.head.state.to_ref() + self.ptr.state() } pub fn handle(&mut self, rule: D) -> Head<&Q, &S> @@ -29,30 +36,34 @@ impl Actor { S: Symbolic, { self.write(rule.value().clone()); - self.head.shift_inplace(rule.direction()); + self.ptr.shift_inplace(rule.direction()); Head { - state: self.head.state.to_ref(), + state: self.ptr.state.to_ref(), symbol: self.read(), } } + pub fn is_empty(&self) -> bool { + self.alpha.is_empty() + } + pub fn is_halted(&self) -> bool { - self.head.symbol >= self.tape.len() + self.ptr.symbol >= self.alpha.len() } pub fn len(&self) -> usize { - self.tape.len() + self.alpha.len() } pub fn read(&self) -> &S { - &self.tape[self.head.symbol % self.len()] + &self.alpha[self.ptr.symbol % self.len()] } pub fn write(&mut self, symbol: S) { - if self.head.symbol < self.tape.len() { - self.tape[self.head.symbol] = symbol; + if self.ptr.symbol < self.alpha.len() { + self.alpha[self.ptr.symbol] = symbol; } else { - self.tape.push(symbol); + self.alpha.push(symbol); } } } diff --git a/core/src/rules/instruction.rs b/core/src/rules/instruction.rs index da797d7..2106c8c 100644 --- a/core/src/rules/instruction.rs +++ b/core/src/rules/instruction.rs @@ -47,7 +47,7 @@ impl Instruction { } /// Returns the current [state](State) of the [head](Head) pub fn state(&self) -> State<&'_ Q> { - self.head().get_state() + self.head().state() } /// Returns the current symbol of the [head](Head) pub const fn symbol(&self) -> &S { diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index c191f2b..ee01861 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -127,7 +127,7 @@ impl Directive for Instruction { impl Header for crate::Head { fn current_state(&self) -> State<&'_ Q> { - self.state().to_ref() + self.state() } fn symbol(&self) -> &S { diff --git a/core/src/rules/parts/head.rs b/core/src/rules/parts/head.rs index fd67dfa..5f66306 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/rules/parts/head.rs @@ -55,16 +55,12 @@ impl Head { self.symbol = symbol; } /// Returns a reference to the current [state](State) - pub fn get_state(&self) -> State<&'_ Q> { + pub fn state(&self) -> State<&Q> { self.state.to_ref() } - - 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 + pub fn state_mut(&mut self) -> State<&mut Q> { + self.state.to_mut() } /// Returns a reference to the current symbol pub const fn symbol(&self) -> &S { diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 9871772..9d7be9a 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -79,6 +79,7 @@ impl Program { pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.ruleset.iter_mut() } + pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> where Q: PartialEq, diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index e0435af..fa56c00 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -24,21 +24,22 @@ pub(crate) mod prelude { pub type AnyState = State>; #[doc(hidden)] -pub trait StateData { - type Data; +pub trait RawState { + type Ctx; + } #[doc(hidden)] pub trait Stateful { - type State: StateData; + type State: RawState; } /* ************* Implementations ************* */ -impl StateData for State { - type Data = Q; +impl RawState for State { + type Ctx = Q; } impl Stateful for State { diff --git a/core/src/state/states/halting.rs b/core/src/state/states/halting.rs index f2def94..6b35120 100644 --- a/core/src/state/states/halting.rs +++ b/core/src/state/states/halting.rs @@ -2,7 +2,7 @@ Appellation: halting Contrib: FL03 */ -use crate::state::State; +use crate::state::{RawState, State, Stateful}; #[doc(hidden)] pub trait Halting { @@ -28,7 +28,14 @@ impl Halt { pub fn as_mut(&mut self) -> &mut T { &mut self.0 } +} + +impl RawState for Halt { + type Ctx = Q; +} +impl Stateful for Halt { + type State = Halt; } impl Halting for Halt { diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index 2102db5..f81bf3c 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -25,14 +25,13 @@ pub trait Alphabet: IntoIterator { fn to_vec(&self) -> Vec; } -/// [Symbolic] is a generic trait automatically implemented for any -/// type that satisfies the following conditions: -/// - Clone -/// - Eq -/// - Ord +/// [Symbolic] is a trait denoting types that can be used as symbols; +/// this is useful for allowing symbols to represented with [char] or +/// be a position on the tape, value mapping for an alphabet,. pub trait Symbolic where Self: Clone + + Copy + Eq + Ord + PartialEq @@ -60,15 +59,15 @@ pub trait Symbol: Symbolic { ************* Implementations ************* */ -impl Alphabet for Vec { - type Sym = char; +impl Alphabet for Vec { + type Sym = S; - fn to_vec(&self) -> Vec { + fn to_vec(&self) -> Vec { self.clone() } } impl Symbolic for S where - S: Clone + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash + S: Copy + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash { } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 270297b..ba92465 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -82,7 +82,7 @@ impl TM { loop { #[cfg(feature = "tracing")] tracing::info!("{}", &self.tape); - match self.next() { + match self.process() { Some(_) => { if self.state.is_halt() { return Ok(()); @@ -101,7 +101,7 @@ impl TM { feature = "tracing", tracing::instrument(skip_all, name = "step", target = "turing") )] - fn process(&mut self) -> Option> + fn process(&mut self) -> Option> where Q: Clone + PartialEq + 'static, S: Clone + PartialEq, @@ -114,7 +114,7 @@ impl TM { // Get the first instruction for the current head if let Some(tail) = self.program.get_head_ref(self.read()?) { self.state = self.tape.update_inplace(tail.cloned()); - return Some(tail.cloned().into_head()); + return self.read(); } unreachable!("No instruction found for the current head") } @@ -123,25 +123,11 @@ impl TM { impl core::iter::Iterator for TM where Q: Clone + PartialEq + 'static, - S: Symbolic, + S: Clone + PartialEq, { type Item = Head; - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "turing") - )] fn next(&mut self) -> Option { - #[cfg(feature = "tracing")] - tracing::info!("Stepping..."); - if self.state.is_halt() { - return None; - } - // Get the first instruction for the current head - if let Some(tail) = self.program.get_head_ref(self.read()?) { - self.state = self.tape.update_inplace(tail.cloned()); - return Some(tail.cloned().into_head()); - } - unreachable!("No instruction found for the current head") + self.process().map(|i| i.cloned()) } } From 387cc4e5deebd730ba82eced3f1bbc3bc815d023 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 31 Jul 2024 11:52:38 -0500 Subject: [PATCH 13/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 10 ++++------ core/src/actors/exec.rs | 36 ++++++++++++++++++++++++++++++++++++ core/src/actors/mod.rs | 35 +++-------------------------------- core/src/traits/actor.rs | 8 ++++++++ core/src/traits/symbolic.rs | 22 ++++++---------------- 5 files changed, 57 insertions(+), 54 deletions(-) create mode 100644 core/src/actors/exec.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 632beb1..4fb0623 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -24,18 +24,16 @@ impl Actor { &self.ptr } - - pub fn state(&self) -> State<&Q> { self.ptr.state() } - pub fn handle(&mut self, rule: D) -> Head<&Q, &S> + pub fn handle(&mut self, rule: &D) -> Head<&Q, &S> where D: Directive, S: Symbolic, { - self.write(rule.value().clone()); + self.write(*rule.value()); self.ptr.shift_inplace(rule.direction()); Head { state: self.ptr.state.to_ref(), @@ -47,8 +45,8 @@ impl Actor { self.alpha.is_empty() } - pub fn is_halted(&self) -> bool { - self.ptr.symbol >= self.alpha.len() + pub fn is_halted(&self) -> bool where Q: 'static { + self.ptr.state.is_halt() } pub fn len(&self) -> usize { diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs new file mode 100644 index 0000000..08d8630 --- /dev/null +++ b/core/src/actors/exec.rs @@ -0,0 +1,36 @@ +/* + Appellation: exec + Contrib: FL03 +*/ +use super::Actor; +use crate::{Head, Program, Symbolic}; + +pub struct Executor { + pub(crate) actor: Actor, + pub(crate) program: Program, +} + +impl Executor { + + pub fn with_program(self, program: Program) -> Self { + Executor { program, ..self } + } +} + +impl Iterator for Executor +where + Q: Clone + PartialEq + 'static, + S: Symbolic, +{ + type Item = Head; + + fn next(&mut self) -> Option { + if self.actor.is_halted() { + return None; + } + let state = self.actor.state(); + let symbol = self.actor.read(); + let rule = self.program.get(state, symbol)?; + Some(self.actor.handle(rule).cloned()) + } +} diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 9a75760..8f72410 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -3,42 +3,13 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::actor::Actor; +pub use self::{actor::Actor, exec::Executor}; pub(crate) mod actor; +pub(crate) mod exec; #[allow(unused_imports)] pub(crate) mod prelude { pub use super::actor::Actor; -} - -use crate::{Program, Symbolic}; - -pub struct Model { - pub actor: Actor, - pub program: Program, -} - -impl Model { - pub fn with_program(self, program: Program) -> Self { - Model { program, ..self } - } -} -impl Iterator for Model -where - Q: Clone + PartialEq, - S: Symbolic, -{ - type Item = S; - - fn next(&mut self) -> Option { - if self.actor.is_halted() { - return None; - } - let state = self.actor.state(); - let symbol = self.actor.read(); - let rule = self.program.get(state, symbol)?; - self.actor.handle(rule.clone()); - unimplemented!() - } + pub use super::exec::Executor; } diff --git a/core/src/traits/actor.rs b/core/src/traits/actor.rs index d127e0a..2a0b5ad 100644 --- a/core/src/traits/actor.rs +++ b/core/src/traits/actor.rs @@ -8,3 +8,11 @@ pub trait RawSpace { fn space(&self) -> Self::Elem; } + + + +pub trait ConfigSpace { + type Space; + + +} \ No newline at end of file diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index f81bf3c..11dccc4 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -15,7 +15,7 @@ /// a particular value. The values of the variants may then be used /// as pointers, specifiying the location of the symbol w.r.t. the /// alphabet. -pub trait Alphabet: IntoIterator { +pub trait Alphabet { type Sym; fn len(&self) -> usize { @@ -38,23 +38,13 @@ where + PartialOrd + core::fmt::Debug + core::fmt::Display - + core::hash::Hash, + + core::hash::Hash + + Send + + Sync + + 'static { } -#[doc(hidden)] -pub trait Symbol: Symbolic { - type Z; - - fn symbol(&self) -> char; - - fn is_symbol(&self, symbol: char) -> bool { - self.symbol() == symbol - } - /// Returns the value assigned to the symbol; - fn value(&self) -> Self::Z; -} - /* ************* Implementations ************* */ @@ -68,6 +58,6 @@ impl Alphabet for Vec { } impl Symbolic for S where - S: Copy + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash + S: Copy + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash + Send + Sync + 'static { } From f80fed801c6bb79ff9116de4637b9542b620fe3d Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 11 Aug 2024 10:03:02 -0500 Subject: [PATCH 14/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 27 ++++++++++- core/src/actors/exec.rs | 9 ++++ core/src/macros/fmt.rs | 1 - core/src/rules/program.rs | 8 +++- core/src/state/mod.rs | 13 +++++- core/src/state/state.rs | 10 +++- core/src/state/states/halting.rs | 61 +++++++++++++++++-------- core/src/tape/cursor.rs | 48 +++++++++++++++++++ core/src/tape/ds.rs | 10 ++++ core/src/tape/entry.rs | 29 ------------ core/src/tape/iter.rs | 10 ---- core/src/tape/mod.rs | 13 ++++-- core/src/tape/tape.rs | 21 +++++---- core/src/traits/{actor.rs => cspace.rs} | 6 +-- core/src/traits/mod.rs | 2 +- core/src/traits/symbolic.rs | 12 ++++- rstm/Cargo.toml | 2 +- rstm/src/turing.rs | 3 +- rstm/src/turing/state.rs | 48 +++++++++++++++++++ rstm/tests/actor.rs | 30 ++++++++++++ 20 files changed, 276 insertions(+), 87 deletions(-) create mode 100644 core/src/tape/cursor.rs create mode 100644 core/src/tape/ds.rs delete mode 100644 core/src/tape/entry.rs delete mode 100644 core/src/tape/iter.rs rename core/src/traits/{actor.rs => cspace.rs} (95%) create mode 100644 rstm/src/turing/state.rs create mode 100644 rstm/tests/actor.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 4fb0623..465ccb1 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -2,7 +2,8 @@ Appellation: actor Contrib: FL03 */ -use crate::rules::Directive; +use super::Executor; +use crate::rules::{Directive, Program}; use crate::{Head, State, Symbolic}; /// [Actor] aptly describe the `TMH` model @@ -20,6 +21,17 @@ impl Actor { } } + pub fn from_state(State(state): State) -> Self { + Self::new(State(state), Vec::new()) + } + + pub fn from_tape(tape: impl IntoIterator) -> Self + where + Q: Default, + { + Self::new(State::default(), tape) + } + pub const fn head(&self) -> &Head { &self.ptr } @@ -41,11 +53,22 @@ impl Actor { } } + pub fn run(self, program: Program) -> Executor + where + Q: Clone + Default + PartialEq + 'static, + S: Symbolic, + { + Executor::from_actor(self).with_program(program) + } + pub fn is_empty(&self) -> bool { self.alpha.is_empty() } - pub fn is_halted(&self) -> bool where Q: 'static { + pub fn is_halted(&self) -> bool + where + Q: 'static, + { self.ptr.state.is_halt() } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 08d8630..9075e46 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -11,6 +11,15 @@ pub struct Executor { } impl Executor { + pub fn from_actor(actor: Actor) -> Self + where + Q: Default, + { + Self { + actor, + program: Program::new(), + } + } pub fn with_program(self, program: Program) -> Self { Executor { program, ..self } diff --git a/core/src/macros/fmt.rs b/core/src/macros/fmt.rs index 82c1ac8..4b00c44 100644 --- a/core/src/macros/fmt.rs +++ b/core/src/macros/fmt.rs @@ -15,4 +15,3 @@ macro_rules! unit_impl_fmt { $(impl_fmt!(@impl $trait::<$T>($($fmt)*));)* }; } - diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 9d7be9a..be4ce8f 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -79,7 +79,7 @@ impl Program { pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.ruleset.iter_mut() } - + pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> where Q: PartialEq, @@ -184,6 +184,12 @@ impl From> for Program { } } +impl Extend> for Program { + fn extend>>(&mut self, iter: I) { + self.ruleset.extend(iter) + } +} + impl FromIterator> for Program where Q: Default, diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index fa56c00..69dba89 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -26,7 +26,15 @@ pub type AnyState = State>; #[doc(hidden)] pub trait RawState { type Ctx; +} +pub trait Stated: RawState { + fn cloned(&self) -> Self + where + Q: Clone; + fn copied(&self) -> Self + where + Q: Copy; } #[doc(hidden)] @@ -34,10 +42,13 @@ pub trait Stateful { type State: RawState; } - /* ************* Implementations ************* */ +impl RawState for Halt { + type Ctx = Q; +} + impl RawState for State { type Ctx = Q; } diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 058c807..d7d86b6 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -97,7 +97,10 @@ impl State { { core::any::TypeId::of::() } - pub fn is_halt(&self) -> bool where Q: 'static { + pub fn is_halt(&self) -> bool + where + Q: 'static, + { core::any::TypeId::of::() == core::any::TypeId::of::>>() } } @@ -107,7 +110,10 @@ impl State> { pub fn halt(Halt(inner): Halt) -> Self { Self(Halt(inner)) } - + + pub fn unhalt(self) -> State { + State(self.0.into_inner()) + } } impl<'a, Q> State<&'a Q> { diff --git a/core/src/state/states/halting.rs b/core/src/state/states/halting.rs index 6b35120..cca0a8a 100644 --- a/core/src/state/states/halting.rs +++ b/core/src/state/states/halting.rs @@ -2,46 +2,69 @@ Appellation: halting Contrib: FL03 */ -use crate::state::{RawState, State, Stateful}; +use crate::state::{RawState, State}; #[doc(hidden)] -pub trait Halting { +pub trait Haltable { const HALT: bool = true; + type State: RawState; + private!(); - } +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Halt(pub Q); -pub struct Halt(pub T); - -impl Halt { - pub fn new(halt: T) -> Self { +impl Halt { + pub fn new(halt: Q) -> Self { Self(halt) } - pub fn into_inner(self) -> T { + + pub fn into_inner(self) -> Q { self.0 } - pub fn as_ref(&self) -> &T { - &self.0 + + pub fn as_ref<'a>(&'a self) -> Halt<&'a Q> { + Halt(&self.0) } - pub fn as_mut(&mut self) -> &mut T { - &mut self.0 + + pub fn as_mut<'a>(&'a mut self) -> Halt<&'a mut Q> { + Halt(&mut self.0) } -} -impl RawState for Halt { - type Ctx = Q; + pub fn as_state<'a>(&'a self) -> State> { + State(Halt(&self.0)) + } + + pub fn cloned(&self) -> Self + where + Q: Clone, + { + Self(self.0.clone()) + } + + pub fn copied(&self) -> Self + where + Q: Copy, + { + Self(self.0) + } } -impl Stateful for Halt { - type State = Halt; +impl From> for Halt { + fn from(State(state): State) -> Self { + Self(state) + } } -impl Halting for Halt { +impl Haltable for Halt { + type State = State; seal!(); } -impl Halting for State> { +impl Haltable for State> { + type State = State; seal!(); } diff --git a/core/src/tape/cursor.rs b/core/src/tape/cursor.rs new file mode 100644 index 0000000..608e14d --- /dev/null +++ b/core/src/tape/cursor.rs @@ -0,0 +1,48 @@ +/* + Appellation: cursor + Contrib: FL03 +*/ + +/// [Cursor] contains contextual information about the position of the head of a tape. +/// +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Cursor { + pub(crate) pos: usize, + pub(crate) ptr: *mut T, + pub(crate) step: usize, +} + +impl Cursor { + pub fn new(ptr: *mut T) -> Self { + Self { + pos: 0, + ptr, + step: 0, + } + } + + pub fn from_vec(vec: &mut Vec) -> Self { + Self::new(vec.as_mut_ptr()) + } + + pub fn pointer(&self) -> *mut T { + self.ptr + } + + pub fn position(&self) -> usize { + self.pos + } + + pub fn step(&self) -> usize { + self.step + } + + pub fn update(&mut self, cursor: usize) { + self.pos = cursor; + self.next(); + } + + fn next(&mut self) { + self.step += 1; + } +} diff --git a/core/src/tape/ds.rs b/core/src/tape/ds.rs new file mode 100644 index 0000000..395360c --- /dev/null +++ b/core/src/tape/ds.rs @@ -0,0 +1,10 @@ +/* + Appellation: ds + Contrib: FL03 +*/ +#![allow(unused)] +/// [DoubleTape] preserves the input, recording all actions taken on a seperate tape. +pub struct DoubleTape { + pub(crate) inputs: Vec, + pub(crate) output: Vec, +} diff --git a/core/src/tape/entry.rs b/core/src/tape/entry.rs deleted file mode 100644 index 14c4474..0000000 --- a/core/src/tape/entry.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - Appellation: entry - Contrib: FL03 -*/ -#![allow(unused)] -use crate::Instruction; - -pub struct Entry<'a, Q, S> { - key: &'a mut usize, - value: &'a mut Instruction, -} - -impl<'a, Q, S> Entry<'a, Q, S> { - pub fn new(key: &'a mut usize, value: &'a mut Instruction) -> Self { - Self { key, value } - } - - pub fn key(&self) -> &usize { - &self.key - } - - pub fn set_key(&mut self, key: usize) { - *self.key = key; - } - - pub fn set_value(&mut self, value: Instruction) { - *self.value = value; - } -} diff --git a/core/src/tape/iter.rs b/core/src/tape/iter.rs deleted file mode 100644 index 913a600..0000000 --- a/core/src/tape/iter.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - Appellation: iter - Contrib: FL03 -*/ -#![allow(dead_code)] - -pub struct Iter<'a, T> { - tape: &'a T, - index: usize, -} diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index e183d3b..5622443 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -12,18 +12,21 @@ pub use self::tape::Tape; pub(crate) mod tape; #[doc(hidden)] -pub mod entry; +pub mod cursor; #[doc(hidden)] -pub mod iter; +pub mod ds; pub(crate) mod prelude { pub use super::tape::Tape; } +/// A trait for tape-like structures. #[doc(hidden)] pub trait RawTape { type Elem; + private!(); + fn as_slice(&self) -> &[Self::Elem]; } @@ -33,6 +36,8 @@ pub trait RawTape { impl RawTape for [T] { type Elem = T; + seal!(); + fn as_slice(&self) -> &[Self::Elem] { &self } @@ -41,7 +46,9 @@ impl RawTape for [T] { impl RawTape for Vec { type Elem = T; + seal!(); + fn as_slice(&self) -> &[Self::Elem] { - &self + Vec::as_slice(self) } } diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index ad03638..6ca769c 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -5,15 +5,12 @@ use crate::{Direction, Error, Head, State, Tail}; use core::cell::Cell; -/// [StdTape] is an implementation of the traditional tape described by Turing machines. +/// The [`Tape`] is defined to be a one-dimensional surface evenly divided into cells capable +/// of storing symbols. The tape is infinite in both directions allowing the head, or actor, to +/// move without bounds, extending the tape as needed. /// -/// The tape, often thought of as the memory of the machine, is a one-dimensional array -/// of symbols in-which the tape head can read and write symbols. Furthermore, the tape -/// is infinite in both directions, meaning that the tape head can move left or right. -/// While this setup is largely hypothetical, it is a useful abstraction for understanding -/// the capabilities of Turing machines. /// -/// Here, the [StdTape] employs the use of a [Vec] to store symbols while leveraging a +/// Here, the [Tape] employs the use of a [Vec] to store symbols while leveraging a /// [usize] to keep track of the current position of the tape head. Moreover, the tape /// stores the number of steps or operations taken by the tape head in a [Cell]. /// This is done to quantify the impact of operations whose directions are defined to @@ -82,11 +79,17 @@ impl Tape { pub fn is_empty(&self) -> bool { self.store.is_empty() } - + /// Returns an immutable iterator over the symbols stored on the tape. pub fn iter(&self) -> core::slice::Iter { self.store.iter() } - + /// Returns a mutable iterator over the symbols stored on the tape. + pub fn iter_mut(&mut self) -> core::slice::IterMut { + self.store.iter_mut() + } + /// Returns the number of steps or operations taken by the tape head; + /// this provides a measure of the impact of operations whose directions are defined to be + /// [Stay](Direction::Stay). pub fn ticks(&self) -> usize { self.ticks.get() } diff --git a/core/src/traits/actor.rs b/core/src/traits/cspace.rs similarity index 95% rename from core/src/traits/actor.rs rename to core/src/traits/cspace.rs index 2a0b5ad..31af39b 100644 --- a/core/src/traits/actor.rs +++ b/core/src/traits/cspace.rs @@ -9,10 +9,6 @@ pub trait RawSpace { fn space(&self) -> Self::Elem; } - - pub trait ConfigSpace { type Space; - - -} \ No newline at end of file +} diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 1042dc1..bcd5904 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -6,7 +6,7 @@ pub use self::symbolic::*; #[doc(hidden)] -pub mod actor; +pub mod cspace; #[doc(hidden)] pub mod io; pub mod symbolic; diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index 11dccc4..d6f2070 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -41,7 +41,7 @@ where + core::hash::Hash + Send + Sync - + 'static + + 'static, { } @@ -58,6 +58,14 @@ impl Alphabet for Vec { } impl Symbolic for S where - S: Copy + Eq + Ord + core::fmt::Debug + core::fmt::Display + core::hash::Hash + Send + Sync + 'static + S: Copy + + Eq + + Ord + + core::fmt::Debug + + core::fmt::Display + + core::hash::Hash + + Send + + Sync + + 'static { } diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index cdd9878..a554795 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -84,7 +84,7 @@ version = "0.1" # ****************** Dev Dependencies ****************** [dev-dependencies] lazy_static.workspace = true -tracing-subscriber = { features = [], version = "0.3" } +tracing-subscriber = "0.3" [package.metadata.docs.rs] all-features = true diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index ba92465..c0c80b0 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -2,9 +2,10 @@ Appellation: tm Contrib: FL03 */ -pub use self::model::Turing; +pub use self::{model::Turing, state::TMS}; pub(crate) mod model; +pub(crate) mod state; use crate::prelude::{Error, Head, Symbolic, Tape}; use crate::rules::Program; diff --git a/rstm/src/turing/state.rs b/rstm/src/turing/state.rs new file mode 100644 index 0000000..c1b9651 --- /dev/null +++ b/rstm/src/turing/state.rs @@ -0,0 +1,48 @@ +/* + Appellation: turing + Contrib: FL03 +*/ +use crate::state::{Halt, State}; + +/// [TMS] extends the T +#[derive( + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + strum::AsRefStr, + strum::EnumCount, + strum::EnumIs, +)] +pub enum TMS { + Halt(State>), + State(State), +} + +impl TMS { + pub fn halt(State(state): State>) -> Self { + TMS::Halt(State(state)) + } + + pub fn state(state: State) -> Self { + TMS::State(state) + } + + pub fn into_halt(self) -> State> { + match self { + TMS::Halt(state) => state, + TMS::State(state) => State(Halt(state.into_inner())), + } + } + + pub fn into_state(self) -> State { + match self { + TMS::Halt(state) => state.unhalt(), + TMS::State(state) => state, + } + } +} diff --git a/rstm/tests/actor.rs b/rstm/tests/actor.rs new file mode 100644 index 0000000..bd340ef --- /dev/null +++ b/rstm/tests/actor.rs @@ -0,0 +1,30 @@ +/* + Appellation: actor + Contrib: FL03 +*/ + +use lazy_static::lazy_static; +use rstm::actors::Actor; +use rstm::state::BinState; +use rstm::{rule, Program, State}; + +use BinState::{Invalid, Valid}; + +lazy_static! { + static ref ALPHA: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + static ref RULES: Program = Program::from_iter([ + rule![(Invalid, 0) -> Right(Invalid, 0)], + rule![(Invalid, 1) -> Right(Valid, 0)], + rule![(Valid, 0) -> Right(Valid, 1)], + rule![(Valid, 1) -> Left(Valid, 0)], + ]); +} + +#[should_panic] +#[test] +fn test_actor() { + let input = [0_usize; 10]; + + let actor = Actor::new(State(Invalid), input); + actor.run(RULES.clone()); +} From 5d93e4f34d2fe03fdc4e05a329821d33e3c56fd3 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 11 Aug 2024 10:38:26 -0500 Subject: [PATCH 15/35] update Signed-off-by: Joe McCain III --- core/src/state/state.rs | 14 ++++++++++++-- core/src/tape/tape.rs | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/src/state/state.rs b/core/src/state/state.rs index d7d86b6..6afc978 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -26,7 +26,15 @@ impl State { pub fn boxed(self) -> State> { State(Box::new(self.0)) } - /// Consumes and returns the inner value of the [state](State). + /// Returns a halted state with an immutable reference to the state. + pub fn as_halt<'a>(&'a self) -> State> { + State(Halt(self)) + } + /// Consumes the state and returns a halted state. + pub fn into_halt(self) -> State> { + State(Halt(self.into_inner())) + } + /// Consumes and returns the inner value of the state. pub fn into_inner(self) -> Q { self.0 } @@ -85,7 +93,6 @@ impl State { pub fn to_ref<'a>(&'a self) -> State<&'a Q> { State(&self.0) } - /// Returns the `name` of the generic inner type, `Q`. pub fn inner_type_name(&self) -> &'static str { core::any::type_name::() @@ -97,12 +104,15 @@ impl State { { core::any::TypeId::of::() } + /// Returns `true` if the state is a [Halt] state. pub fn is_halt(&self) -> bool where Q: 'static, { core::any::TypeId::of::() == core::any::TypeId::of::>>() } + + } impl State> { diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 6ca769c..9d079bd 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -5,6 +5,9 @@ use crate::{Direction, Error, Head, State, Tail}; use core::cell::Cell; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + /// The [`Tape`] is defined to be a one-dimensional surface evenly divided into cells capable /// of storing symbols. The tape is infinite in both directions allowing the head, or actor, to /// move without bounds, extending the tape as needed. From 47cee43d3226f20a5b9f569dcc7eaaf8993d525f Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Sun, 11 Aug 2024 11:37:41 -0500 Subject: [PATCH 16/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 15 ++++++++++++-- core/src/state/state.rs | 2 +- core/src/state/states/binary.rs | 36 +++++++++++++++++---------------- rstm/examples/basic.rs | 33 +++++++++++++++++++++--------- rstm/tests/actor.rs | 16 +++++++-------- 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 465ccb1..60fb403 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -71,7 +71,7 @@ impl Actor { { self.ptr.state.is_halt() } - + #[inline] pub fn len(&self) -> usize { self.alpha.len() } @@ -81,10 +81,21 @@ impl Actor { } pub fn write(&mut self, symbol: S) { - if self.ptr.symbol < self.alpha.len() { + let head = self.head(); + if head.symbol < self.len() { self.alpha[self.ptr.symbol] = symbol; } else { self.alpha.push(symbol); } } + + fn get(&mut self, index: Head) -> &S where S: Clone + Default { + if index.symbol >= self.len() { + let diff = index.symbol - self.len(); + let ext = vec![S::default(); diff + 1]; + self.alpha.extend(ext); + } + &self.alpha[index.symbol % self.len()] + } } + diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 6afc978..6638870 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -27,7 +27,7 @@ impl State { State(Box::new(self.0)) } /// Returns a halted state with an immutable reference to the state. - pub fn as_halt<'a>(&'a self) -> State> { + pub fn as_halt(&self) -> State> { State(Halt(self)) } /// Consumes the state and returns a halted state. diff --git a/core/src/state/states/binary.rs b/core/src/state/states/binary.rs index c667768..0fd63d7 100644 --- a/core/src/state/states/binary.rs +++ b/core/src/state/states/binary.rs @@ -44,23 +44,23 @@ use crate::State; ) )] pub enum BinaryState { - Invalid(State), - Valid(State), + Invalid(I), + Valid(V), } impl BinaryState { - pub fn invalid(State(state): State) -> Self { - Self::Invalid(State(state)) + pub fn invalid(state: I) -> Self { + Self::Invalid(state) } - pub fn valid(State(state): State) -> Self { - Self::Valid(State(state)) + pub fn valid(state: V) -> Self { + Self::Valid(state) } pub fn invalidate(self, state: Q) -> BinaryState { match self { - Self::Invalid(_) => BinaryState::Invalid(State(state)), - Self::Valid(_) => BinaryState::Invalid(State(state)), + Self::Invalid(_) => BinaryState::Invalid(state), + Self::Valid(_) => BinaryState::Invalid(state), } } @@ -75,8 +75,8 @@ impl BinaryState { impl BinaryState { pub fn into_inner(self) -> State { match self { - Self::Invalid(q) => q, - Self::Valid(q) => q, + Self::Invalid(q) => State(q), + Self::Valid(q) => State(q), } } @@ -85,11 +85,7 @@ impl BinaryState { } } -impl Default for BinState { - fn default() -> Self { - Self::Invalid - } -} + impl AsRef for BinaryState { fn as_ref(&self) -> &Q { @@ -121,9 +117,15 @@ impl core::borrow::BorrowMut for BinaryState { } } -impl Default for BinaryState { +impl Default for BinState { + fn default() -> Self { + Self::Invalid + } +} + +impl Default for BinaryState where I: Default { fn default() -> Self { - Self::invalid(State::default()) + Self::invalid(::default()) } } diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index f62a6a1..ec29981 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,26 +4,39 @@ */ extern crate rstm; -use rstm::state::BinState::{Invalid, Valid}; use rstm::{rule, Program, State, Tape, TM}; +lazy_static::lazy_static! { + static ref RULES: Program = Program::from_iter([ + rule![(0, 0) -> Right(0, 0)], + rule![(0, 1) -> Right(1, 0)], + rule![(1, 0) -> Right(0, 1)], + rule![(1, 1) -> Left(1, 0)], + rule![(-1, 0) -> Right(0, 1)], + rule![(-1, 1) -> Stay(0, 0)], + ]); +} + + fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); // initialize the tape data - let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; + let alpha = [0_usize; 10]; // define the rules for the machine - let rules = vec![ - rule![(Invalid, 0) -> Right(Invalid, 0)], - rule![(Invalid, 1) -> Right(Valid, 0)], - rule![(Valid, 0) -> Right(Valid, 1)], - rule![(Valid, 1) -> Left(Valid, 0)], - ]; + let rules = Program::from_iter([ + rule![(0, 0) -> Right(0, 1)], + rule![(0, 1) -> Right(1, 0)], + + rule![(1, 0) -> Right(-1, 1)], + rule![(1, 1) -> Left(1, 0)], + rule![(-1, 0) -> Right(0, 1)], + rule![(-1, 1) -> Stay(0, 0)], + ]).with_initial_state(State(0)); let tape = Tape::from_iter(alpha); - let program = Program::from_state(State(Invalid)).with_instructions(rules); // create a new instance of the machine - let tm = TM::new(program, tape); + let tm = TM::new(rules, tape); tm.execute()?; Ok(()) } diff --git a/rstm/tests/actor.rs b/rstm/tests/actor.rs index bd340ef..31f514d 100644 --- a/rstm/tests/actor.rs +++ b/rstm/tests/actor.rs @@ -5,18 +5,18 @@ use lazy_static::lazy_static; use rstm::actors::Actor; -use rstm::state::BinState; use rstm::{rule, Program, State}; -use BinState::{Invalid, Valid}; lazy_static! { static ref ALPHA: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; - static ref RULES: Program = Program::from_iter([ - rule![(Invalid, 0) -> Right(Invalid, 0)], - rule![(Invalid, 1) -> Right(Valid, 0)], - rule![(Valid, 0) -> Right(Valid, 1)], - rule![(Valid, 1) -> Left(Valid, 0)], + static ref RULES: Program = Program::from_iter([ + rule![(0, 0) -> Right(0, 0)], + rule![(0, 1) -> Right(1, 0)], + rule![(1, 0) -> Right(0, 1)], + rule![(1, 1) -> Left(1, 0)], + rule![(-1, 0) -> Right(0, 1)], + rule![(-1, 1) -> Stay(0, 0)], ]); } @@ -25,6 +25,6 @@ lazy_static! { fn test_actor() { let input = [0_usize; 10]; - let actor = Actor::new(State(Invalid), input); + let actor = Actor::new(State(0), input); actor.run(RULES.clone()); } From 662afd25a466924a31c8ca660e6890419b79ee27 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 14 Aug 2024 09:04:05 -0500 Subject: [PATCH 17/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 162 +++++++++++++++++++++++--------- core/src/actors/exec.rs | 3 +- core/src/state/state.rs | 2 - core/src/state/states/binary.rs | 7 +- rstm/examples/basic.rs | 5 +- rstm/tests/actor.rs | 5 +- 6 files changed, 129 insertions(+), 55 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 60fb403..f4e39eb 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -2,6 +2,9 @@ Appellation: actor Contrib: FL03 */ +#[doc(inline)] +pub use self::builder::ActorBuilder; + use super::Executor; use crate::rules::{Directive, Program}; use crate::{Head, State, Symbolic}; @@ -9,93 +12,168 @@ use crate::{Head, State, Symbolic}; /// [Actor] aptly describe the `TMH` model pub struct Actor { /// the input alphabet - pub alpha: Vec, - pub ptr: Head, + pub(crate) alpha: Vec, + /// the head of the tape + pub(crate) head: Head, } impl Actor { - pub fn new(State(state): State, tape: impl IntoIterator) -> Self { - Self { - alpha: Vec::from_iter(tape), - ptr: Head::new(State(state), 0), - } - } - - pub fn from_state(State(state): State) -> Self { - Self::new(State(state), Vec::new()) - } - - pub fn from_tape(tape: impl IntoIterator) -> Self + pub fn new() -> ActorBuilder where Q: Default, { - Self::new(State::default(), tape) + ActorBuilder::new() } + pub fn from_state(State(state): State) -> ActorBuilder { + ActorBuilder::from_state(State(state)) + } + /// Returns an immutable reference to the tape alphabet as a slice + pub fn alpha(&self) -> &[S] { + &self.alpha + } + /// Returns an immutable reference to the head of the tape pub const fn head(&self) -> &Head { - &self.ptr + &self.head } - + /// Returns a mutable reference to the head of the tape + pub fn head_mut(&mut self) -> &mut Head { + &mut self.head + } + /// Returns the current state of the tape pub fn state(&self) -> State<&Q> { - self.ptr.state() + self.head.state() } - + /// Returns a mutable reference to the current state of the tape + pub fn state_mut(&mut self) -> State<&mut Q> { + self.head.state_mut() + } + /// Performs a single step of the Turing machine pub fn handle(&mut self, rule: &D) -> Head<&Q, &S> where D: Directive, S: Symbolic, { self.write(*rule.value()); - self.ptr.shift_inplace(rule.direction()); - Head { - state: self.ptr.state.to_ref(), - symbol: self.read(), - } + self.head.shift_inplace(rule.direction()); + self.read().expect("Invalid head position") } - - pub fn run(self, program: Program) -> Executor + /// Executes the given program; the method is lazy, meaning it will not compute immediately + /// but will return an [Executor] that is better suited for managing the runtime. + pub fn exec(self, program: Program) -> Executor where Q: Clone + Default + PartialEq + 'static, S: Symbolic, { - Executor::from_actor(self).with_program(program) + Executor { + actor: self, + program, + } } - + /// Checks if the tape is empty pub fn is_empty(&self) -> bool { self.alpha.is_empty() } - + /// Checks if the tape is halted pub fn is_halted(&self) -> bool where Q: 'static, { - self.ptr.state.is_halt() + self.head.state.is_halt() } + /// Returns the length of the tape #[inline] pub fn len(&self) -> usize { self.alpha.len() } - - pub fn read(&self) -> &S { - &self.alpha[self.ptr.symbol % self.len()] + /// Reads the current symbol at the head of the tape + pub fn read(&self) -> Option> { + self.alpha.get(self.head.symbol).map(|symbol| Head { + state: self.head.state.to_ref(), + symbol, + }) } - + /// Writes the given symbol to the tape pub fn write(&mut self, symbol: S) { let head = self.head(); if head.symbol < self.len() { - self.alpha[self.ptr.symbol] = symbol; + self.alpha[self.head.symbol] = symbol; } else { + // append to the tape self.alpha.push(symbol); } } +} + +mod builder { + use super::*; + use std::iter::FromIterator; + + pub struct ActorBuilder { + alpha: Vec, + head: Head, + } + + impl ActorBuilder { + pub fn new() -> Self + where + Q: Default, + { + Self { + alpha: Vec::new(), + head: Head::default(), + } + } + + pub fn from_state(State(state): State) -> Self { + Self { + alpha: Vec::new(), + head: Head::new(State(state), 0), + } + } - fn get(&mut self, index: Head) -> &S where S: Clone + Default { - if index.symbol >= self.len() { - let diff = index.symbol - self.len(); - let ext = vec![S::default(); diff + 1]; - self.alpha.extend(ext); + pub fn alpha(self, alpha: I) -> Self + where + I: IntoIterator, + { + Self { + alpha: Vec::from_iter(alpha), + ..self + } + } + + pub fn head(self, head: Head) -> Self { + Self { head, ..self } + } + + pub fn state(self, State(state): State) -> Self { + Self { + head: Head { + state: State(state), + ..self.head + }, + ..self + } + } + + pub fn position(self, symbol: usize) -> Self { + Self { + head: Head { + symbol, + ..self.head + }, + ..self + } + } + + pub fn build(self) -> Actor + where + Q: Default, + { + Actor { + alpha: self.alpha, + head: self.head, + } } - &self.alpha[index.symbol % self.len()] } } - diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 9075e46..6e9c1ac 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -37,8 +37,7 @@ where if self.actor.is_halted() { return None; } - let state = self.actor.state(); - let symbol = self.actor.read(); + let Head { state, symbol } = self.actor.read()?; let rule = self.program.get(state, symbol)?; Some(self.actor.handle(rule).cloned()) } diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 6638870..1fd2fe5 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -111,8 +111,6 @@ impl State { { core::any::TypeId::of::() == core::any::TypeId::of::>>() } - - } impl State> { diff --git a/core/src/state/states/binary.rs b/core/src/state/states/binary.rs index 0fd63d7..939ced3 100644 --- a/core/src/state/states/binary.rs +++ b/core/src/state/states/binary.rs @@ -85,8 +85,6 @@ impl BinaryState { } } - - impl AsRef for BinaryState { fn as_ref(&self) -> &Q { match self { @@ -123,7 +121,10 @@ impl Default for BinState { } } -impl Default for BinaryState where I: Default { +impl Default for BinaryState +where + I: Default, +{ fn default() -> Self { Self::invalid(::default()) } diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index ec29981..3740458 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -17,7 +17,6 @@ lazy_static::lazy_static! { ]); } - fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); @@ -27,12 +26,12 @@ fn main() -> Result<(), Box> { let rules = Program::from_iter([ rule![(0, 0) -> Right(0, 1)], rule![(0, 1) -> Right(1, 0)], - rule![(1, 0) -> Right(-1, 1)], rule![(1, 1) -> Left(1, 0)], rule![(-1, 0) -> Right(0, 1)], rule![(-1, 1) -> Stay(0, 0)], - ]).with_initial_state(State(0)); + ]) + .with_initial_state(State(0)); let tape = Tape::from_iter(alpha); // create a new instance of the machine diff --git a/rstm/tests/actor.rs b/rstm/tests/actor.rs index 31f514d..6ea6f81 100644 --- a/rstm/tests/actor.rs +++ b/rstm/tests/actor.rs @@ -7,7 +7,6 @@ use lazy_static::lazy_static; use rstm::actors::Actor; use rstm::{rule, Program, State}; - lazy_static! { static ref ALPHA: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; static ref RULES: Program = Program::from_iter([ @@ -25,6 +24,6 @@ lazy_static! { fn test_actor() { let input = [0_usize; 10]; - let actor = Actor::new(State(0), input); - actor.run(RULES.clone()); + let actor = Actor::new().alpha(input).state(State(0)).build(); + actor.exec(RULES.clone()); } From df2e923a102ace02dfe1ba2e4f0da3578c289982 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 15 Aug 2024 09:23:29 -0500 Subject: [PATCH 18/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 11 ++++------- core/src/actors/exec.rs | 2 +- core/src/actors/mod.rs | 1 - core/src/lib.rs | 5 +++-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index f4e39eb..5895329 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -9,7 +9,7 @@ use super::Executor; use crate::rules::{Directive, Program}; use crate::{Head, State, Symbolic}; -/// [Actor] aptly describe the `TMH` model +/// An [Actor] describes a Turing machine with a moving head (TMH). pub struct Actor { /// the input alphabet pub(crate) alpha: Vec, @@ -49,7 +49,7 @@ impl Actor { self.head.state_mut() } /// Performs a single step of the Turing machine - pub fn handle(&mut self, rule: &D) -> Head<&Q, &S> + pub fn step(&mut self, rule: &D) -> Head<&Q, &S> where D: Directive, S: Symbolic, @@ -60,11 +60,7 @@ impl Actor { } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. - pub fn exec(self, program: Program) -> Executor - where - Q: Clone + Default + PartialEq + 'static, - S: Symbolic, - { + pub fn exec(self, program: Program) -> Executor { Executor { actor: self, program, @@ -109,6 +105,7 @@ mod builder { use super::*; use std::iter::FromIterator; + #[derive(Default)] pub struct ActorBuilder { alpha: Vec, head: Head, diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 6e9c1ac..a480cb5 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -39,6 +39,6 @@ where } let Head { state, symbol } = self.actor.read()?; let rule = self.program.get(state, symbol)?; - Some(self.actor.handle(rule).cloned()) + Some(self.actor.step(rule).cloned()) } } diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 8f72410..0a0ed04 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -8,7 +8,6 @@ pub use self::{actor::Actor, exec::Executor}; pub(crate) mod actor; pub(crate) mod exec; -#[allow(unused_imports)] pub(crate) mod prelude { pub use super::actor::Actor; pub use super::exec::Executor; diff --git a/core/src/lib.rs b/core/src/lib.rs index 4ebda0f..6d5e11d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -11,8 +11,8 @@ extern crate alloc; #[doc(inline)] pub use self::{ - error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::Tape, traits::prelude::*, - types::prelude::*, + actors::Actor, error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::Tape, + traits::prelude::*, types::prelude::*, }; #[macro_use] @@ -31,6 +31,7 @@ pub mod traits; pub mod types; pub mod prelude { + pub use crate::actors::prelude::*; pub use crate::error::Error; pub use crate::ops::prelude::*; pub use crate::rules::prelude::*; From c0d7029ec286d670abfe3f6a927e7e589ce20f27 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 15 Aug 2024 09:33:21 -0500 Subject: [PATCH 19/35] update Signed-off-by: Joe McCain III --- core/src/rules/instruction.rs | 1 + core/src/rules/mod.rs | 27 ++++++-------------- core/src/rules/program.rs | 22 ++++++++-------- core/src/tape/cursor.rs | 48 ----------------------------------- core/src/tape/ds.rs | 10 -------- core/src/tape/mod.rs | 5 ---- 6 files changed, 21 insertions(+), 92 deletions(-) delete mode 100644 core/src/tape/cursor.rs delete mode 100644 core/src/tape/ds.rs diff --git a/core/src/rules/instruction.rs b/core/src/rules/instruction.rs index 2106c8c..c6e8374 100644 --- a/core/src/rules/instruction.rs +++ b/core/src/rules/instruction.rs @@ -69,6 +69,7 @@ impl Instruction { mod builder { use super::*; + #[derive(Default)] pub struct InstructionBuilder { direction: Direction, state: Option>, diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index ee01861..f225a56 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -28,20 +28,6 @@ pub(crate) mod prelude { use crate::{Direction, State, Symbolic}; -pub trait Space { - type Elem; - type State; - - fn state(&self) -> State<&'_ Self::State>; - - fn symbol(&self) -> &Self::Elem; -} - -pub trait Morphism { - type Input: Space; - type Output: Space; -} - pub trait Transition where S: Symbolic, @@ -57,12 +43,15 @@ where fn write_symbol(&self) -> &S; } -pub trait Header { +/// The [`Scope`] trait is used to describe objects containing information or references to the +/// current state and symbol of a Turing machine. +pub trait Scope { fn current_state(&self) -> State<&'_ Q>; fn symbol(&self) -> &S; } +/// [`Directive`] is a trait describing the `tail` of a typical Turing machine; pub trait Directive { fn direction(&self) -> Direction; @@ -77,7 +66,7 @@ pub trait Directive { impl Transition for A where - A: Header + Directive, + A: Scope + Directive, S: Symbolic, { fn direction(&self) -> Direction { @@ -101,7 +90,7 @@ where } } -impl Header for Instruction { +impl Scope for Instruction { fn current_state(&self) -> State<&'_ Q> { self.head.state.to_ref() } @@ -125,7 +114,7 @@ impl Directive for Instruction { } } -impl Header for crate::Head { +impl Scope for crate::Head { fn current_state(&self) -> State<&'_ Q> { self.state() } @@ -149,7 +138,7 @@ impl Directive for crate::Tail { } } -impl Header for (State, S) { +impl Scope for (State, S) { fn current_state(&self) -> State<&'_ Q> { self.0.to_ref() } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index be4ce8f..6e2ebb9 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -6,13 +6,15 @@ use super::Instruction; use crate::{Head, State, Tail}; use std::vec; -type RuleSet = Vec>; +type Ruleset = Vec>; + +// type Ruleset = std::collections::HashMap, Tail>; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { pub initial_state: State, - pub(crate) ruleset: RuleSet, + pub(crate) ruleset: Ruleset, } impl Program { @@ -32,14 +34,14 @@ impl Program { { Self { initial_state: State::default(), - ruleset: RuleSet::from_iter(instructions), + ruleset: Ruleset::from_iter(instructions), } } pub fn from_state(State(initial_state): State) -> Self { Self { initial_state: State(initial_state), - ruleset: RuleSet::new(), + ruleset: Ruleset::new(), } } /// @@ -55,7 +57,7 @@ impl Program { instructions: impl IntoIterator>, ) -> Self { Self { - ruleset: RuleSet::from_iter(instructions), + ruleset: Ruleset::from_iter(instructions), ..self } } @@ -64,11 +66,11 @@ impl Program { self.initial_state.to_ref() } /// Returns a reference to the instructions. - pub const fn instructions(&self) -> &RuleSet { + pub const fn instructions(&self) -> &Ruleset { &self.ruleset } /// Returns a mutable reference to the instructions. - pub fn instructions_mut(&mut self) -> &mut RuleSet { + pub fn instructions_mut(&mut self) -> &mut Ruleset { &mut self.ruleset } /// Returns an iterator over the elements. @@ -175,8 +177,8 @@ where } } -impl From> for Program { - fn from(instructions: RuleSet) -> Self { +impl From> for Program { + fn from(instructions: Ruleset) -> Self { Self { initial_state: State::default(), ruleset: instructions, @@ -197,7 +199,7 @@ where fn from_iter>>(iter: I) -> Self { Self { initial_state: State::default(), - ruleset: RuleSet::from_iter(iter), + ruleset: Ruleset::from_iter(iter), } } } diff --git a/core/src/tape/cursor.rs b/core/src/tape/cursor.rs deleted file mode 100644 index 608e14d..0000000 --- a/core/src/tape/cursor.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Appellation: cursor - Contrib: FL03 -*/ - -/// [Cursor] contains contextual information about the position of the head of a tape. -/// -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Cursor { - pub(crate) pos: usize, - pub(crate) ptr: *mut T, - pub(crate) step: usize, -} - -impl Cursor { - pub fn new(ptr: *mut T) -> Self { - Self { - pos: 0, - ptr, - step: 0, - } - } - - pub fn from_vec(vec: &mut Vec) -> Self { - Self::new(vec.as_mut_ptr()) - } - - pub fn pointer(&self) -> *mut T { - self.ptr - } - - pub fn position(&self) -> usize { - self.pos - } - - pub fn step(&self) -> usize { - self.step - } - - pub fn update(&mut self, cursor: usize) { - self.pos = cursor; - self.next(); - } - - fn next(&mut self) { - self.step += 1; - } -} diff --git a/core/src/tape/ds.rs b/core/src/tape/ds.rs deleted file mode 100644 index 395360c..0000000 --- a/core/src/tape/ds.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - Appellation: ds - Contrib: FL03 -*/ -#![allow(unused)] -/// [DoubleTape] preserves the input, recording all actions taken on a seperate tape. -pub struct DoubleTape { - pub(crate) inputs: Vec, - pub(crate) output: Vec, -} diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 5622443..8a862bb 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -11,11 +11,6 @@ pub use self::tape::Tape; pub(crate) mod tape; -#[doc(hidden)] -pub mod cursor; -#[doc(hidden)] -pub mod ds; - pub(crate) mod prelude { pub use super::tape::Tape; } From df9e1a031ed577ffc6ee47d1573bfaf0e9efa82f Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 15 Aug 2024 16:44:13 -0500 Subject: [PATCH 20/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 2 +- core/src/rules/mod.rs | 6 +-- core/src/rules/parts/head.rs | 8 ++-- core/src/rules/parts/tail.rs | 8 ++-- core/src/rules/program.rs | 2 +- core/src/state/state.rs | 75 +++++++++++++++----------------- core/src/state/states/halting.rs | 56 ++++++++++++++++++++---- rstm/src/turing.rs | 4 +- 8 files changed, 97 insertions(+), 64 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 5895329..fe568a8 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -85,7 +85,7 @@ impl Actor { /// Reads the current symbol at the head of the tape pub fn read(&self) -> Option> { self.alpha.get(self.head.symbol).map(|symbol| Head { - state: self.head.state.to_ref(), + state: self.head.state.view(), symbol, }) } diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index f225a56..03d2e41 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -92,7 +92,7 @@ where impl Scope for Instruction { fn current_state(&self) -> State<&'_ Q> { - self.head.state.to_ref() + self.head.state.view() } fn symbol(&self) -> &S { @@ -140,7 +140,7 @@ impl Directive for crate::Tail { impl Scope for (State, S) { fn current_state(&self) -> State<&'_ Q> { - self.0.to_ref() + self.0.view() } fn symbol(&self) -> &S { @@ -154,7 +154,7 @@ impl Directive for (Direction, State, S) { } fn next_state(&self) -> State<&'_ Q> { - self.1.to_ref() + self.1.view() } fn value(&self) -> &S { diff --git a/core/src/rules/parts/head.rs b/core/src/rules/parts/head.rs index 5f66306..5a8aa3f 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/rules/parts/head.rs @@ -56,11 +56,11 @@ impl Head { } /// Returns a reference to the current [state](State) pub fn state(&self) -> State<&Q> { - self.state.to_ref() + self.state.view() } /// Returns a mutable reference to the current [state](State) pub fn state_mut(&mut self) -> State<&mut Q> { - self.state.to_mut() + self.state.view_mut() } /// Returns a reference to the current symbol pub const fn symbol(&self) -> &S { @@ -82,14 +82,14 @@ impl Head { pub fn to_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { Head { - state: self.state.to_ref(), + state: self.state.view(), symbol: &self.symbol, } } pub fn to_mut<'a>(&'a mut self) -> Head<&'a mut Q, &'a mut S> { Head { - state: self.state.to_mut(), + state: self.state.view_mut(), symbol: &mut self.symbol, } } diff --git a/core/src/rules/parts/tail.rs b/core/src/rules/parts/tail.rs index 1c89fc9..8041c76 100644 --- a/core/src/rules/parts/tail.rs +++ b/core/src/rules/parts/tail.rs @@ -48,7 +48,7 @@ impl Tail { } /// Returns the next [state](State) the agent is instructed to move to pub fn next_state(&self) -> State<&'_ Q> { - self.state.to_ref() + self.state.view() } /// Returns the symbol the [head](Head) is instructed to write pub const fn write_symbol(&self) -> &S { @@ -61,13 +61,13 @@ impl Tail { /// Returns an instance of the [head](Head) where each element within /// the created instance is an immutable reference pub fn to_head_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { - super::Head::new(self.state.to_ref(), &self.symbol) + super::Head::new(self.state.view(), &self.symbol) } pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { Tail { direction: self.direction, - state: self.state.to_ref(), + state: self.state.view(), symbol: &self.symbol, } } @@ -75,7 +75,7 @@ impl Tail { pub fn to_mut(&mut self) -> Tail<&'_ mut Q, &'_ mut S> { Tail { direction: self.direction, - state: self.state.to_mut(), + state: self.state.view_mut(), symbol: &mut self.symbol, } } diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 6e2ebb9..791fb50 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -63,7 +63,7 @@ impl Program { } /// Returns an owned reference to the initial state of the program. pub fn initial_state(&self) -> State<&'_ Q> { - self.initial_state.to_ref() + self.initial_state.view() } /// Returns a reference to the instructions. pub const fn instructions(&self) -> &Ruleset { diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 1fd2fe5..3034a3a 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -14,17 +14,22 @@ impl State { pub fn new(state: Q) -> Self { Self(state) } + /// Returns an immutable reference to the state. - pub fn as_ref(&self) -> &Q { + pub const fn get(&self) -> &Q { &self.0 } /// Returns a mutable reference to the state. - pub fn as_mut(&mut self) -> &mut Q { + pub fn get_mut(&mut self) -> &mut Q { &mut self.0 } - /// Consumes the state and returns a boxed state. - pub fn boxed(self) -> State> { - State(Box::new(self.0)) + /// Consumes and returns the inner value of the state. + pub fn into_inner(self) -> Q { + self.0 + } + /// Sets the state to a new value. + pub fn set(&mut self, state: Q) { + self.0 = state; } /// Returns a halted state with an immutable reference to the state. pub fn as_halt(&self) -> State> { @@ -34,20 +39,9 @@ impl State { pub fn into_halt(self) -> State> { State(Halt(self.into_inner())) } - /// Consumes and returns the inner value of the state. - pub fn into_inner(self) -> Q { - self.0 - } - /// Consumes the state and returns an owned state. - pub fn into_owned(self) -> State - where - Q: Clone, - { - State(self.0.clone()) - } - /// Transforms the state into a shared reference. - pub fn into_shared(self) -> State> { - State(Arc::new(self.0)) + /// Returns a new state with a boxed inner value. + pub fn boxed(self) -> State> { + State(Box::new(self.0)) } /// [State::map] applies a [`Fn`] closure to the state, returing a new state in the process. /// Essentially, the method sufficiently describes the transformation of the state. @@ -62,7 +56,7 @@ impl State { where F: FnMut(&mut Q) -> R, { - State(f(self.as_mut())) + State(f(self.get_mut())) } /// Maps the state to a new state using a closure that takes the state by value. pub fn map_once(self, f: F) -> State @@ -71,12 +65,9 @@ impl State { { State(f(self)) } - /// Returns a state with an owned inner value. - pub fn to_owned(&self) -> State - where - Q: Clone, - { - State(self.0.clone()) + /// Wraps the inner value of the state with an [`Arc`] and returns a new instance of [State] + pub fn shared(self) -> State> { + State(Arc::new(self.0)) } /// Returns a shared reference to the state. pub fn to_shared(&self) -> State> @@ -85,25 +76,29 @@ impl State { { State(Arc::new(self.0.clone())) } - /// Returns a state with a mutable reference to the inner value. - pub fn to_mut<'a>(&'a mut self) -> State<&'a mut Q> { - State(&mut self.0) - } /// Returns a state with an owned inner value. - pub fn to_ref<'a>(&'a self) -> State<&'a Q> { + pub fn view<'a>(&'a self) -> State<&'a Q> { State(&self.0) + } + /// Returns a state with a mutable reference to the inner value. + pub fn view_mut<'a>(&'a mut self) -> State<&'a mut Q> { + State(&mut self.0) } /// Returns the `name` of the generic inner type, `Q`. - pub fn inner_type_name(&self) -> &'static str { + pub fn get_inner_type_name(&self) -> &'static str { core::any::type_name::() } /// Returns the `type id` of the generic inner type, `Q`. - pub fn inner_type_id(&self) -> core::any::TypeId + pub fn get_inner_type_id(&self) -> core::any::TypeId where Q: 'static, { core::any::TypeId::of::() } + /// Wraps the inner value with a [Halt] state, returning a new instance of [State]. + pub fn halt(self) -> State> { + State(Halt(self.0)) + } /// Returns `true` if the state is a [Halt] state. pub fn is_halt(&self) -> bool where @@ -114,11 +109,11 @@ impl State { } impl State> { - /// Returns a new instance of [State] with a [Halt] sub-state. - pub fn halt(Halt(inner): Halt) -> Self { + /// Creates a new instance of [State] from a [Halt] state. + pub fn halted(Halt(inner): Halt) -> Self { Self(Halt(inner)) } - + pub fn unhalt(self) -> State { State(self.0.into_inner()) } @@ -222,21 +217,21 @@ where Q: PartialEq, { fn eq(&self, other: &Q) -> bool { - self.0 == *other + self.get().eq(other) } } impl PartialOrd for State where - Q: PartialOrd, + Q: PartialOrd, { fn partial_cmp(&self, other: &Q) -> Option { - self.0.partial_cmp(other) + self.get().partial_cmp(other) } } impl From for State { fn from(state: Q) -> Self { - Self(state) + State(state) } } diff --git a/core/src/state/states/halting.rs b/core/src/state/states/halting.rs index cca0a8a..979c709 100644 --- a/core/src/state/states/halting.rs +++ b/core/src/state/states/halting.rs @@ -26,30 +26,68 @@ impl Halt { self.0 } - pub fn as_ref<'a>(&'a self) -> Halt<&'a Q> { - Halt(&self.0) + pub const fn get(&self) -> &Q { + &self.0 } - pub fn as_mut<'a>(&'a mut self) -> Halt<&'a mut Q> { - Halt(&mut self.0) + pub fn get_mut(&mut self) -> &mut Q { + &mut self.0 } - pub fn as_state<'a>(&'a self) -> State> { + pub fn set(&mut self, halt: Q) { + self.0 = halt; + } + /// Converts the halted state into a new [State] with an immutable reference to the inner value. + pub fn as_state(&self) -> State> { State(Halt(&self.0)) } + /// Converts the halted state into a new [State] with a mutable reference to the inner value. + pub fn as_state_mut(&mut self) -> State> { + State(Halt(&mut self.0)) + } + /// Wraps the halted state and returns a new [State] + pub fn into_state(self) -> State> { + State(self) + } + /// Returns an instance of [`Halt`] with an immutable reference to the inner value. + pub fn view<'a>(&'a self) -> Halt<&'a Q> { + Halt(&self.0) + } + /// Returns an instance of [`Halt`] with a mutable reference to the inner value. + pub fn view_mut<'a>(&'a mut self) -> Halt<&'a mut Q> { + Halt(&mut self.0) + } +} + +impl<'a, Q> Halt<&'a Q> { + pub fn cloned(&self) -> Halt + where + Q: Clone, + { + Halt(self.0.clone()) + } + + pub fn copied(&self) -> Halt + where + Q: Copy, + { + Halt(*self.0) + } +} - pub fn cloned(&self) -> Self +impl<'a, Q> Halt<&'a mut Q> { + pub fn cloned(&self) -> Halt where Q: Clone, { - Self(self.0.clone()) + Halt(self.0.clone()) } - pub fn copied(&self) -> Self + pub fn copied(&self) -> Halt where Q: Copy, { - Self(self.0) + Halt(*self.0) } } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index c0c80b0..1beed32 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -51,12 +51,12 @@ impl TM { /// Returns an instance of the [state](State) with an immutable /// reference to the internal data pub fn state(&self) -> State<&'_ Q> { - self.state.to_ref() + self.state.view() } /// Returns an instance of the [state](State) with a mutable /// reference to the internal data pub fn state_mut(&mut self) -> State<&'_ mut Q> { - self.state.to_mut() + self.state.view_mut() } /// Returns an immutable reference to the [tape](StdTape) pub const fn tape(&self) -> &Tape { From 8178f6abda97acdcd56e821e32bc498e0b2b2020 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 15 Aug 2024 17:23:17 -0500 Subject: [PATCH 21/35] update Signed-off-by: Joe McCain III --- core/src/state/state.rs | 67 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 3034a3a..1012a9b 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -8,7 +8,7 @@ use std::sync::Arc; #[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 Q); +pub struct State(pub Q); impl State { pub fn new(state: Q) -> Self { @@ -235,3 +235,68 @@ impl From for State { State(state) } } + +macro_rules! impl_ops { + (@impl $trait:ident.$call:ident) => { + impl ::core::ops::$trait for State + where + Q: ::core::ops::$trait, + { + type Output = State; + + fn $call(self, rhs: State) -> Self::Output { + State(::core::ops::$trait::$call(self.0, rhs.0)) + } + } + + impl ::core::ops::$trait for State + where + Q: core::ops::$trait, + { + type Output = State; + + fn $call(self, rhs: Q) -> Self::Output { + State(::core::ops::$trait::$call(self.0, rhs)) + } + } + + paste::paste! { + impl ::core::ops::[<$trait Assign>]> for State + where + Q: ::core::ops::[<$trait Assign>], + { + + fn [<$call _assign>](&mut self, rhs: State) { + ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs.0) + } + } + impl ::core::ops::[<$trait Assign>] for State + where + Q: ::core::ops::[<$trait Assign>], + { + + fn [<$call _assign>](&mut self, rhs: Q) { + ::core::ops::[<$trait Assign>]::[<$call _assign>](self.get_mut(), rhs) + } + } + } + }; + ($($trait:ident.$call:ident),* $(,)?) => { + $( + impl_ops!(@impl $trait.$call); + )* + }; +} + +impl_ops! { + Add.add, + BitAnd.bitand, + BitOr.bitor, + BitXor.bitxor, + Div.div, + Mul.mul, + Rem.rem, + Shl.shl, + Shr.shr, + Sub.sub, +} \ No newline at end of file From a23d2cd382f1f900c9605e67d708eeb914ec1cb3 Mon Sep 17 00:00:00 2001 From: Joe McCain III <92560746+FL03@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:36:00 -0500 Subject: [PATCH 22/35] Update state.rs --- core/src/state/state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 1012a9b..8342e8c 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -47,9 +47,9 @@ impl State { /// Essentially, the method sufficiently describes the transformation of the state. pub fn map(self, f: F) -> State where - F: Fn(State) -> R, + F: Fn(&Q) -> R, { - State(f(self)) + State(f(self.get())) } /// [State::map_mut] applies a [`FnMut`] closure to the state, returing the transformed state. pub fn map_mut(mut self, f: &mut F) -> State From 0bdbe0aa3b1dc1fe0b94be99a37be4664514e0e8 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 16 Aug 2024 12:12:41 -0500 Subject: [PATCH 23/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 107 ++++++++++++--------- core/src/actors/exec.rs | 38 +++++++- core/src/error.rs | 40 ++++++-- core/src/lib.rs | 10 +- core/src/macros.rs | 10 -- core/src/macros/fmt.rs | 7 +- core/src/macros/rules.rs | 49 ++++++++++ core/src/macros/states.rs | 7 ++ core/src/rules/entry.rs | 2 +- core/src/rules/mod.rs | 28 ++---- core/src/rules/program.rs | 37 ++++--- core/src/rules/{instruction.rs => rule.rs} | 18 ++-- core/src/state/state.rs | 10 +- core/src/tape/tape.rs | 18 +++- core/src/types/direction.rs | 36 +++++-- core/src/{rules/parts => types}/head.rs | 20 ++-- core/src/types/mod.rs | 8 +- core/src/{rules/parts => types}/tail.rs | 8 +- core/tests/actor.rs | 36 +++++++ rstm/Cargo.toml | 14 +-- rstm/examples/actor.rs | 44 +++++++++ rstm/examples/basic.rs | 41 ++++---- rstm/examples/utm.rs | 81 ---------------- rstm/src/lib.rs | 17 ++-- rstm/src/macros/rules.rs | 25 ----- rstm/src/turing.rs | 8 +- rstm/tests/actor.rs | 29 ------ 27 files changed, 429 insertions(+), 319 deletions(-) delete mode 100644 core/src/macros.rs create mode 100644 core/src/macros/rules.rs rename core/src/rules/{instruction.rs => rule.rs} (91%) rename core/src/{rules/parts => types}/head.rs (91%) rename core/src/{rules/parts => types}/tail.rs (96%) create mode 100644 core/tests/actor.rs create mode 100644 rstm/examples/actor.rs delete mode 100644 rstm/examples/utm.rs delete mode 100644 rstm/src/macros/rules.rs delete mode 100644 rstm/tests/actor.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index fe568a8..c6c01c5 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -7,9 +7,10 @@ pub use self::builder::ActorBuilder; use super::Executor; use crate::rules::{Directive, Program}; -use crate::{Head, State, Symbolic}; +use crate::{Head, State}; /// An [Actor] describes a Turing machine with a moving head (TMH). +#[derive(Clone, Debug)] pub struct Actor { /// the input alphabet pub(crate) alpha: Vec, @@ -18,10 +19,7 @@ pub struct Actor { } impl Actor { - pub fn new() -> ActorBuilder - where - Q: Default, - { + pub fn new() -> ActorBuilder { ActorBuilder::new() } @@ -36,6 +34,13 @@ impl Actor { pub const fn head(&self) -> &Head { &self.head } + + pub fn head_ref(&self) -> Head<&Q, usize> { + Head { + state: self.head.state.to_ref(), + symbol: self.head.symbol, + } + } /// Returns a mutable reference to the head of the tape pub fn head_mut(&mut self) -> &mut Head { &mut self.head @@ -49,22 +54,23 @@ impl Actor { self.head.state_mut() } /// Performs a single step of the Turing machine - pub fn step(&mut self, rule: &D) -> Head<&Q, &S> + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "actor") + )] + pub fn step(&mut self, rule: &D) -> Option> where D: Directive, - S: Symbolic, + S: Clone, { - self.write(*rule.value()); + self.write(rule.value().clone()); self.head.shift_inplace(rule.direction()); - self.read().expect("Invalid head position") + self.read() } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. - pub fn exec(self, program: Program) -> Executor { - Executor { - actor: self, - program, - } + pub fn execute(self, program: Program) -> Executor { + Executor::new(self, program) } /// Checks if the tape is empty pub fn is_empty(&self) -> bool { @@ -83,20 +89,30 @@ impl Actor { self.alpha.len() } /// Reads the current symbol at the head of the tape + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "read", target = "actor") + )] pub fn read(&self) -> Option> { - self.alpha.get(self.head.symbol).map(|symbol| Head { - state: self.head.state.view(), - symbol, - }) + #[cfg(feature = "tracing")] + tracing::info!("Reading the tape..."); + let Head { state, symbol } = self.head_ref(); + self.alpha.get(symbol).map(|value| Head::new(state, value)) } /// Writes the given symbol to the tape - pub fn write(&mut self, symbol: S) { - let head = self.head(); - if head.symbol < self.len() { - self.alpha[self.head.symbol] = symbol; + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "write", target = "actor") + )] + pub fn write(&mut self, value: S) { + let pos = self.head.symbol; + if pos < self.len() { + self.alpha[pos] = value; } else { + #[cfg(feature = "tracing")] + tracing::info!("Appending to the tape..."); // append to the tape - self.alpha.push(symbol); + self.alpha.push(value); } } } @@ -108,24 +124,24 @@ mod builder { #[derive(Default)] pub struct ActorBuilder { alpha: Vec, - head: Head, + state: Option>, + symbol: usize, } impl ActorBuilder { - pub fn new() -> Self - where - Q: Default, - { + pub fn new() -> Self { Self { alpha: Vec::new(), - head: Head::default(), + state: None, + symbol: 0, } } pub fn from_state(State(state): State) -> Self { Self { alpha: Vec::new(), - head: Head::new(State(state), 0), + state: Some(State(state)), + symbol: 0, } } @@ -140,36 +156,39 @@ mod builder { } pub fn head(self, head: Head) -> Self { - Self { head, ..self } + Self { + state: Some(head.state), + symbol: head.symbol, + ..self + } } pub fn state(self, State(state): State) -> Self { Self { - head: Head { - state: State(state), - ..self.head - }, + state: Some(State(state)), ..self } } pub fn position(self, symbol: usize) -> Self { - Self { - head: Head { - symbol, - ..self.head - }, - ..self - } + Self { symbol, ..self } } pub fn build(self) -> Actor where Q: Default, { + let ActorBuilder { + alpha, + state, + symbol, + } = self; Actor { - alpha: self.alpha, - head: self.head, + alpha, + head: Head { + state: state.unwrap_or_default(), + symbol, + }, } } } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index a480cb5..6df30d6 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ use super::Actor; -use crate::{Head, Program, Symbolic}; +use crate::{Error, Head, Program, Symbolic}; pub struct Executor { pub(crate) actor: Actor, @@ -11,6 +11,9 @@ pub struct Executor { } impl Executor { + pub(crate) fn new(actor: Actor, program: Program) -> Self { + Self { actor, program } + } pub fn from_actor(actor: Actor) -> Self where Q: Default, @@ -24,6 +27,31 @@ impl Executor { pub fn with_program(self, program: Program) -> Self { Executor { program, ..self } } + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "run", target = "actor") + )] + pub fn run(&mut self) -> Result, Error> + where + Q: Clone + PartialEq + 'static, + S: Symbolic, + { + #[cfg(feature = "tracing")] + tracing::info!("Executing the program using the given actor..."); + loop { + match self.next() { + Some(_) => continue, + None => { + if self.actor.is_halted() { + break; + } else { + return Err(Error::runtime_error("Unknown Error".to_string())); + } + } + } + } + Ok(self.actor.alpha().to_vec()) + } } impl Iterator for Executor @@ -33,12 +61,18 @@ where { type Item = Head; + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "next", target = "actor") + )] fn next(&mut self) -> Option { if self.actor.is_halted() { + #[cfg(feature = "tracing")] + tracing::info!("Halted"); return None; } let Head { state, symbol } = self.actor.read()?; let rule = self.program.get(state, symbol)?; - Some(self.actor.step(rule).cloned()) + self.actor.step(rule).map(|h| h.cloned()) } } diff --git a/core/src/error.rs b/core/src/error.rs index 02c87a1..2f1ec4c 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -2,6 +2,16 @@ Appellation: error Contrib: FL03 */ +#[derive( + Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::VariantNames, thiserror::Error, +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum StateError { + #[error("Invalid State: {0}")] + InvalidState(String), + #[error("State Not Found")] + StateNotFound, +} #[derive( Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::VariantNames, thiserror::Error, @@ -10,10 +20,10 @@ pub enum Error { #[error("[IndexError] Out of Bounds: {index} is out of bounds for a length of {len}")] IndexOutOfBounds { index: usize, len: usize }, - #[error("[StateError] Invalid State: {0}")] - InvalidState(String), - #[error("[StateError] State Not Found")] - StateNotFound, + #[error("[Runtime] Runtime Error: {0}")] + RuntimeError(String), + #[error("State Error: {0}")] + StateError(#[from] StateError), #[error("Transformation error: {0}")] TransformationError(String), #[error("Unknown error: {0}")] @@ -25,12 +35,12 @@ impl Error { Error::IndexOutOfBounds { index, len } } - pub fn invalid_state(err: impl ToString) -> Self { - Error::InvalidState(err.to_string()) + pub fn runtime_error(message: impl ToString) -> Self { + Error::RuntimeError(message.to_string()) } - pub fn state_not_found() -> Self { - Error::StateNotFound + pub fn state_error(err: StateError) -> Self { + Error::StateError(err) } pub fn transformation_error(message: impl ToString) -> Self { @@ -40,6 +50,14 @@ impl Error { pub fn unknown(message: impl ToString) -> Self { Error::Unknown(message.to_string()) } + + pub fn invalid_state(err: impl ToString) -> Self { + Error::StateError(StateError::InvalidState(err.to_string())) + } + + pub fn state_not_found() -> Self { + Error::StateError(StateError::StateNotFound) + } } impl From<&str> for Error { @@ -47,3 +65,9 @@ impl From<&str> for Error { Error::Unknown(err.to_string()) } } + +impl From for Error { + fn from(err: String) -> Self { + Error::Unknown(err) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 6d5e11d..08ad965 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -15,8 +15,16 @@ pub use self::{ traits::prelude::*, types::prelude::*, }; +#[allow(unused_macros)] #[macro_use] -pub(crate) mod macros; +pub(crate) mod macros { + #[macro_use] + pub mod fmt; + #[macro_use] + pub mod rules; + #[macro_use] + pub mod states; +} #[macro_use] pub(crate) mod seal; diff --git a/core/src/macros.rs b/core/src/macros.rs deleted file mode 100644 index b5dcaa0..0000000 --- a/core/src/macros.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - Appellation: macros - Contrib: FL03 -*/ -#![allow(unused)] - -#[macro_use] -pub mod fmt; -#[macro_use] -pub mod states; diff --git a/core/src/macros/fmt.rs b/core/src/macros/fmt.rs index 4b00c44..a6f07dd 100644 --- a/core/src/macros/fmt.rs +++ b/core/src/macros/fmt.rs @@ -4,14 +4,11 @@ */ macro_rules! unit_impl_fmt { - (@impl $trait:ident::<$T:ty>($($fmt:tt)*)) => { + ($trait:ident::<$T:ty>($fmt:expr)) => { impl core::fmt::$trait for $T { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::$trait::fmt(self, f, $($fmt)*) + $fmt(&self, f) } } }; - ($T:ty: $($trait:ident($($fmt:tt)*)),*) => { - $(impl_fmt!(@impl $trait::<$T>($($fmt)*));)* - }; } diff --git a/core/src/macros/rules.rs b/core/src/macros/rules.rs new file mode 100644 index 0000000..3e1a0d9 --- /dev/null +++ b/core/src/macros/rules.rs @@ -0,0 +1,49 @@ +/* + Appellation: rules + Contrib: FL03 +*/ + +/// [`ruleset!`] is a macro that simplifies the creation of a vector of [`Rules`](crate::Rule). +/// +/// ### Syntax +/// +/// ```ignore +/// ruleset![(state, symbol) -> direction(next_state, write_symbol), ...] +/// ``` +/// +/// ### Example +/// +/// The following example demonstrates the usage of the macro to create a ruleset using three +/// states `{-1, 0, 1}` and two symbols `{0, 1}`. +/// +/// ```rust +/// use rstm::ruleset; +/// +/// let rule = ruleset![ +/// (0, 0) -> Right(1, 1), +/// (0, 1) -> Left(-1, 0), +/// (1, 0) -> Right(1, 1), +/// (1, 1) -> Left(-1, 1), +/// (-1, 0) -> Right(0, 0), +/// (-1, 1) -> Left(0, 1), +/// ]; +/// ``` +#[macro_export] +macro_rules! ruleset { + [@base ($state:expr, $symbol:literal) -> $direction:ident($next:expr, $write:literal)] => { + $crate::rules::Rule::new() + .state($crate::State($state)) + .symbol($symbol) + .write_symbol($write) + .direction($crate::Direction::$direction) + .next_state($crate::State($next)) + .build() + }; + [$( ($state:expr, $symbol:literal $(,)?) -> $direction:ident($next:expr, $write:literal $(,)?) ),* $(,)?] => { + [ + $( + $crate::ruleset![@base ($state, $symbol) -> $direction($next, $write)], + )* + ] + }; +} diff --git a/core/src/macros/states.rs b/core/src/macros/states.rs index fc539d9..ada53e4 100644 --- a/core/src/macros/states.rs +++ b/core/src/macros/states.rs @@ -2,3 +2,10 @@ Appellation: states Contrib: FL03 */ + +#[macro_export] +macro_rules! state { + ($state:expr) => { + $crate::State($state) + }; +} diff --git a/core/src/rules/entry.rs b/core/src/rules/entry.rs index 92be88d..5786e12 100644 --- a/core/src/rules/entry.rs +++ b/core/src/rules/entry.rs @@ -2,7 +2,7 @@ Appellation: entry Contrib: FL03 */ -pub use crate::rules::{Head, Tail}; +pub use crate::{Head, Tail}; pub struct Entry<'a, Q, S> { key: &'a mut Head, diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 03d2e41..9421546 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -3,27 +3,17 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{instruction::*, parts::*, program::*}; +pub use self::{program::*, rule::*}; -pub(crate) mod instruction; pub(crate) mod program; +pub(crate) mod rule; #[doc(hidden)] pub mod entry; -pub mod parts { - pub use self::{head::*, tail::*}; - - pub(crate) mod head; - pub(crate) mod tail; - - pub type IndexedHead = Head; -} - pub(crate) mod prelude { - pub use super::instruction::Instruction; - pub use super::parts::{Head, Tail}; pub use super::program::Program; + pub use super::rule::Rule; } use crate::{Direction, State, Symbolic}; @@ -51,7 +41,7 @@ pub trait Scope { fn symbol(&self) -> &S; } -/// [`Directive`] is a trait describing the `tail` of a typical Turing machine; +/// [`Directive`] is a trait describing the `tail` of a typical Turing machine; pub trait Directive { fn direction(&self) -> Direction; @@ -90,9 +80,9 @@ where } } -impl Scope for Instruction { +impl Scope for Rule { fn current_state(&self) -> State<&'_ Q> { - self.head.state.view() + self.head.state.to_ref() } fn symbol(&self) -> &S { @@ -100,7 +90,7 @@ impl Scope for Instruction { } } -impl Directive for Instruction { +impl Directive for Rule { fn direction(&self) -> Direction { self.direction() } @@ -140,7 +130,7 @@ impl Directive for crate::Tail { impl Scope for (State, S) { fn current_state(&self) -> State<&'_ Q> { - self.0.view() + self.0.to_ref() } fn symbol(&self) -> &S { @@ -154,7 +144,7 @@ impl Directive for (Direction, State, S) { } fn next_state(&self) -> State<&'_ Q> { - self.1.view() + self.1.to_ref() } fn value(&self) -> &S { diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 791fb50..6f3c0a8 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -2,11 +2,11 @@ Appellation: program Contrib: FL03 */ -use super::Instruction; +use super::Rule; use crate::{Head, State, Tail}; use std::vec; -type Ruleset = Vec>; +type Ruleset = Vec>; // type Ruleset = std::collections::HashMap, Tail>; @@ -28,7 +28,7 @@ impl Program { } } - pub fn from_iter(instructions: impl IntoIterator>) -> Self + pub fn from_iter(instructions: impl IntoIterator>) -> Self where Q: Default, { @@ -52,10 +52,7 @@ impl Program { } } /// - pub fn with_instructions( - self, - instructions: impl IntoIterator>, - ) -> Self { + pub fn with_instructions(self, instructions: impl IntoIterator>) -> Self { Self { ruleset: Ruleset::from_iter(instructions), ..self @@ -63,7 +60,7 @@ impl Program { } /// Returns an owned reference to the initial state of the program. pub fn initial_state(&self) -> State<&'_ Q> { - self.initial_state.view() + self.initial_state.to_ref() } /// Returns a reference to the instructions. pub const fn instructions(&self) -> &Ruleset { @@ -74,11 +71,11 @@ impl Program { &mut self.ruleset } /// Returns an iterator over the elements. - pub fn iter(&self) -> core::slice::Iter> { + pub fn iter(&self) -> core::slice::Iter> { self.ruleset.iter() } /// Returns a mutable iterator over the elements. - pub fn iter_mut(&mut self) -> core::slice::IterMut> { + pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.ruleset.iter_mut() } @@ -139,20 +136,20 @@ impl Program { } } -impl AsRef<[Instruction]> for Program { - fn as_ref(&self) -> &[Instruction] { +impl AsRef<[Rule]> for Program { + fn as_ref(&self) -> &[Rule] { &self.ruleset } } -impl AsMut<[Instruction]> for Program { - fn as_mut(&mut self) -> &mut [Instruction] { +impl AsMut<[Rule]> for Program { + fn as_mut(&mut self) -> &mut [Rule] { &mut self.ruleset } } impl core::ops::Deref for Program { - type Target = [Instruction]; + type Target = [Rule]; fn deref(&self) -> &Self::Target { &self.ruleset @@ -186,17 +183,17 @@ impl From> for Program { } } -impl Extend> for Program { - fn extend>>(&mut self, iter: I) { +impl Extend> for Program { + fn extend>>(&mut self, iter: I) { self.ruleset.extend(iter) } } -impl FromIterator> for Program +impl FromIterator> for Program where Q: Default, { - fn from_iter>>(iter: I) -> Self { + fn from_iter>>(iter: I) -> Self { Self { initial_state: State::default(), ruleset: Ruleset::from_iter(iter), @@ -205,7 +202,7 @@ where } impl IntoIterator for Program { - type Item = Instruction; + type Item = Rule; type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { diff --git a/core/src/rules/instruction.rs b/core/src/rules/rule.rs similarity index 91% rename from core/src/rules/instruction.rs rename to core/src/rules/rule.rs index c6e8374..75320cc 100644 --- a/core/src/rules/instruction.rs +++ b/core/src/rules/rule.rs @@ -2,20 +2,20 @@ Appellation: instruction Contrib: FL03 */ -pub use self::builder::InstructionBuilder; +pub use self::builder::RuleBuilder; 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 struct Rule { pub head: Head, pub tail: Tail, } -impl Instruction { - pub fn new() -> InstructionBuilder { - InstructionBuilder::new() +impl Rule { + pub fn new() -> RuleBuilder { + RuleBuilder::new() } /// Returns an immutable reference to the [Head] pub const fn head(&self) -> &Head { @@ -70,7 +70,7 @@ mod builder { use super::*; #[derive(Default)] - pub struct InstructionBuilder { + pub struct RuleBuilder { direction: Direction, state: Option>, symbol: Option, @@ -78,7 +78,7 @@ mod builder { write_symbol: Option, } - impl InstructionBuilder { + impl RuleBuilder { pub fn new() -> Self { Self { direction: Direction::Right, @@ -125,8 +125,8 @@ mod builder { } } - pub fn build(self) -> Instruction { - Instruction { + pub fn build(self) -> Rule { + Rule { head: Head { state: self.state.expect("state is required"), symbol: self.symbol.expect("symbol is required"), diff --git a/core/src/state/state.rs b/core/src/state/state.rs index 8342e8c..52693c6 100644 --- a/core/src/state/state.rs +++ b/core/src/state/state.rs @@ -77,11 +77,11 @@ impl State { State(Arc::new(self.0.clone())) } /// Returns a state with an owned inner value. - pub fn view<'a>(&'a self) -> State<&'a Q> { + pub fn to_ref(&self) -> State<&Q> { State(&self.0) } - /// Returns a state with a mutable reference to the inner value. - pub fn view_mut<'a>(&'a mut self) -> State<&'a mut Q> { + /// Returns a state with a mutable reference to the inner value. + pub fn to_mut(&mut self) -> State<&mut Q> { State(&mut self.0) } /// Returns the `name` of the generic inner type, `Q`. @@ -113,7 +113,7 @@ impl State> { pub fn halted(Halt(inner): Halt) -> Self { Self(Halt(inner)) } - + pub fn unhalt(self) -> State { State(self.0.into_inner()) } @@ -299,4 +299,4 @@ impl_ops! { Shl.shl, Shr.shr, Sub.sub, -} \ No newline at end of file +} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 9d079bd..89c439f 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -147,16 +147,24 @@ impl Tape { (tape, head) } - pub fn update_inplace(&mut self, tail: Tail) -> State { + pub fn update_inplace( + &mut self, + direction: Direction, + state: State, + symbol: S, + ) -> State { + self.write(direction, symbol); + self.shift(direction); + state + } + + pub fn apply_inplace(&mut self, tail: Tail) -> State { let Tail { direction, state, symbol, } = tail; - - self.write(direction, symbol); - self.shift(direction); - state + self.update_inplace(direction, state, symbol) } fn on_update(&self) { diff --git a/core/src/types/direction.rs b/core/src/types/direction.rs index 8b954df..e4014f5 100644 --- a/core/src/types/direction.rs +++ b/core/src/types/direction.rs @@ -30,9 +30,9 @@ pub trait IntoDirection { strum::VariantNames, )] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[repr(i8)] #[strum(serialize_all = "lowercase")] pub enum Direction { + /// Represents a single left shift #[cfg_attr( feature = "serde", serde( @@ -54,6 +54,7 @@ pub enum Direction { alias = "Right" ) )] + /// Represents a single right shift Right = 1, #[default] #[cfg_attr( @@ -66,6 +67,7 @@ pub enum Direction { alias = "Stay" ) )] + /// Represents no movement Stay = 0, } @@ -104,22 +106,38 @@ impl Direction { _ => Self::Stay, } } + /// Converts a [str] value into a [Direction] by matching the value to the corresponding + /// variant; defaults to [`Stay`](Direction::Stay) if the value does not match accepted + /// representations of neither [left](Direction::Left) nor [right](Direction::Right). + pub fn from_str(value: &str) -> Self { + match value { + "left" | "Left" | "LEFT" | "l" | "L" => Self::Left, + "right" | "Right" | "RIGHT" | "r" | "R" => Self::Right, + _ => Self::Stay, + } + } /// Returns a [char] representation of the [direction](Direction). + /// + /// ### standard [char] representation + /// + /// 'L' => [Direction::Left] + /// 'R' => [Direction::Right] + /// 'S' => [Direction::Stay] pub fn as_char(&self) -> char { - (*self).into_char() - } - - pub fn as_str(&self) -> &str { - (*self).as_ref() - } - /// Consumes the instance, returning a [char] representation of the [direction](Direction). - pub fn into_char(self) -> char { match self { Self::Left => 'L', Self::Right => 'R', Self::Stay => 'S', } } + /// Returns a [str] representation of the [direction](Direction). + pub fn as_str(&self) -> &str { + match self { + Self::Left => "left", + Self::Right => "right", + Self::Stay => "stay", + } + } /// Applies the shift to the given position in the [direction](Direction) specified by the /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) /// method. diff --git a/core/src/rules/parts/head.rs b/core/src/types/head.rs similarity index 91% rename from core/src/rules/parts/head.rs rename to core/src/types/head.rs index 5a8aa3f..a2e2647 100644 --- a/core/src/rules/parts/head.rs +++ b/core/src/types/head.rs @@ -56,11 +56,11 @@ impl Head { } /// Returns a reference to the current [state](State) pub fn state(&self) -> State<&Q> { - self.state.view() + self.state.to_ref() } /// Returns a mutable reference to the current [state](State) pub fn state_mut(&mut self) -> State<&mut Q> { - self.state.view_mut() + self.state.to_mut() } /// Returns a reference to the current symbol pub const fn symbol(&self) -> &S { @@ -80,16 +80,24 @@ impl Head { } } - pub fn to_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { + pub fn to_ref<'a>(&'a self) -> Head<&Q, &S> + where + Q: 'a, + S: 'a, + { Head { - state: self.state.view(), + state: self.state.to_ref(), symbol: &self.symbol, } } - pub fn to_mut<'a>(&'a mut self) -> Head<&'a mut Q, &'a mut S> { + pub fn to_mut<'a>(&'a mut self) -> Head<&mut Q, &mut S> + where + Q: 'a, + S: 'a, + { Head { - state: self.state.view_mut(), + state: self.state.to_mut(), symbol: &mut self.symbol, } } diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index 12139cb..f3fdefe 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -3,12 +3,16 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::direction::Direction; +pub use self::{direction::Direction, head::Head, tail::Tail}; pub mod direction; +pub mod head; +pub mod tail; pub(crate) mod prelude { pub use super::direction::Direction; + pub use super::head::Head; + pub use super::tail::Tail; #[allow(unused)] pub(crate) use super::Idx; @@ -16,3 +20,5 @@ pub(crate) mod prelude { /// A type alias generally used to represent the position of a value within a collection. pub(crate) type Idx = usize; +/// +pub type IndexedHead = Head; diff --git a/core/src/rules/parts/tail.rs b/core/src/types/tail.rs similarity index 96% rename from core/src/rules/parts/tail.rs rename to core/src/types/tail.rs index 8041c76..1c89fc9 100644 --- a/core/src/rules/parts/tail.rs +++ b/core/src/types/tail.rs @@ -48,7 +48,7 @@ impl Tail { } /// Returns the next [state](State) the agent is instructed to move to pub fn next_state(&self) -> State<&'_ Q> { - self.state.view() + self.state.to_ref() } /// Returns the symbol the [head](Head) is instructed to write pub const fn write_symbol(&self) -> &S { @@ -61,13 +61,13 @@ impl Tail { /// Returns an instance of the [head](Head) where each element within /// the created instance is an immutable reference pub fn to_head_ref<'a>(&'a self) -> Head<&'a Q, &'a S> { - super::Head::new(self.state.view(), &self.symbol) + super::Head::new(self.state.to_ref(), &self.symbol) } pub fn to_ref(&self) -> Tail<&'_ Q, &'_ S> { Tail { direction: self.direction, - state: self.state.view(), + state: self.state.to_ref(), symbol: &self.symbol, } } @@ -75,7 +75,7 @@ impl Tail { pub fn to_mut(&mut self) -> Tail<&'_ mut Q, &'_ mut S> { Tail { direction: self.direction, - state: self.state.view_mut(), + state: self.state.to_mut(), symbol: &mut self.symbol, } } diff --git a/core/tests/actor.rs b/core/tests/actor.rs new file mode 100644 index 0000000..cefd017 --- /dev/null +++ b/core/tests/actor.rs @@ -0,0 +1,36 @@ +/* + Appellation: actor + Contrib: FL03 +*/ +extern crate rstm_core as rstm; + +use rstm::actors::Actor; +use rstm::rules::{Program, Rule}; +use rstm::{ruleset, State}; + +const INITIAL_STATE: State = State(0); + +lazy_static::lazy_static! { + static ref RULES: [Rule; 6] = ruleset![ + (0, 0) -> Right(1, 1), + (0, 1) -> Left(-1, 0), + (1, 0) -> Right(1, 1), + (1, 1) -> Left(-1, 1), + (-1, 0) -> Right(0, 0), + (-1, 1) -> Left(0, 1), + ]; + + static ref PROGRAM: Program = Program::from_iter(RULES.clone()).with_initial_state(INITIAL_STATE); +} + +#[test] +fn test_actor() { + let input = [0_usize; 10]; + + let program = Program::new() + .with_instructions(RULES.clone()) + .with_initial_state(INITIAL_STATE); + + let actor = Actor::new().alpha(input).state(State(0)).build(); + assert!(actor.execute(program).run().is_ok()); +} diff --git a/rstm/Cargo.toml b/rstm/Cargo.toml index a554795..18c8ec2 100644 --- a/rstm/Cargo.toml +++ b/rstm/Cargo.toml @@ -13,7 +13,9 @@ repository.workspace = true version.workspace = true [features] -default = [] +default = [ + "alloc", +] full = [ "default", @@ -22,9 +24,9 @@ full = [ ] # ********* [FF] Dependencies ********* -# alloc = [ -# "serde?/alloc", -# ] +alloc = [ + "serde?/alloc", +] serde = [ "dep:serde", @@ -50,11 +52,11 @@ doctest = false test = true [[example]] -name = "basic" +name = "actor" required-features = ["tracing"] [[example]] -name = "utm" +name = "basic" required-features = ["tracing"] # ****************** Dependencies ****************** diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs new file mode 100644 index 0000000..e536871 --- /dev/null +++ b/rstm/examples/actor.rs @@ -0,0 +1,44 @@ +/* + Appellation: actor + Contrib: FL03 +*/ +extern crate rstm; + +use rstm::{ruleset, Actor, Program, State}; + +fn main() -> Result<(), Box> { + _tracing(); + // initialize the tape data + let alpha: Vec = vec![0, 1, 1, 0, 1, 0, 1, 0]; + // initialize the state of the machine + let initial_state = State(0); + // define the ruleset for the machine + let rules = ruleset![ + (0, 0) -> Right(0, 0), + (0, 1) -> Right(1, 0), + (1, 0) -> Right(0, 1), + (1, 1) -> Left(1, 0), + (-1, 0) -> Right(0, 1), + (-1, 1) -> Stay(0, 0), + ]; + + let program = Program::new() + .with_initial_state(initial_state) + .with_instructions(rules); + + // create a new instance of the machine + let tm = dbg!(Actor::new().alpha(alpha).state(initial_state).build()); + let out = tm.execute(program).run()?; + println!("{out:?}"); + Ok(()) +} + +fn _tracing() { + let timer = tracing_subscriber::fmt::time::uptime(); + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) + .with_target(false) + .with_timer(timer) + .init(); + tracing::info!("Welcome to rstm!"); +} diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 3740458..4a8cb5b 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,16 +4,16 @@ */ extern crate rstm; -use rstm::{rule, Program, State, Tape, TM}; +use rstm::{ruleset, Program, State, Tape, TM}; lazy_static::lazy_static! { - static ref RULES: Program = Program::from_iter([ - rule![(0, 0) -> Right(0, 0)], - rule![(0, 1) -> Right(1, 0)], - rule![(1, 0) -> Right(0, 1)], - rule![(1, 1) -> Left(1, 0)], - rule![(-1, 0) -> Right(0, 1)], - rule![(-1, 1) -> Stay(0, 0)], + static ref RULES: Program = Program::from_iter(ruleset![ + (0, 0) -> Right(0, 1), + (0, 1) -> Right(1, 0), + (1, 0) -> Right(-1, 1), + (1, 1) -> Left(1, 0), + (-1, 0) -> Right(0, 1), + (-1, 1) -> Stay(0, 0), ]); } @@ -23,19 +23,22 @@ fn main() -> Result<(), Box> { // initialize the tape data let alpha = [0_usize; 10]; // define the rules for the machine - let rules = Program::from_iter([ - rule![(0, 0) -> Right(0, 1)], - rule![(0, 1) -> Right(1, 0)], - rule![(1, 0) -> Right(-1, 1)], - rule![(1, 1) -> Left(1, 0)], - rule![(-1, 0) -> Right(0, 1)], - rule![(-1, 1) -> Stay(0, 0)], - ]) - .with_initial_state(State(0)); - + let rules = ruleset![ + (0, 0) -> Right(0, 1), + (0, 1) -> Right(1, 0), + (1, 0) -> Right(-1, 1), + (1, 1) -> Left(1, 0), + (-1, 0) -> Right(0, 1), + (-1, 1) -> Stay(0, 0), + ]; + // create a new program with the rules + let program = Program::new() + .with_instructions(rules) + .with_initial_state(State(0)); + // create a new tape with the data let tape = Tape::from_iter(alpha); // create a new instance of the machine - let tm = TM::new(rules, tape); + let tm = TM::new(program, tape); tm.execute()?; Ok(()) } diff --git a/rstm/examples/utm.rs b/rstm/examples/utm.rs deleted file mode 100644 index 9083282..0000000 --- a/rstm/examples/utm.rs +++ /dev/null @@ -1,81 +0,0 @@ -/* - Appellation: wolfram - Contrib: FL03 -*/ -extern crate rstm; - -use rstm::state::BinState::{Invalid, Valid}; -use rstm::{rule, Program, State, Tape, TM}; - -fn main() -> Result<(), Box> { - tracing_subscriber::fmt().with_target(false).init(); - - // initialize the tape data - let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; - // define the rules for the machine - let rules = vec![ - rule![(Invalid, 0) -> Right(Invalid, 0)], - rule![(Invalid, 1) -> Right(Valid, 0)], - rule![(Valid, 0) -> Right(Valid, 1)], - rule![(Valid, 1) -> Left(Valid, 0)], - ]; - - let tape = Tape::from_iter(alpha); - let program = Program::from_state(State(Invalid)).with_instructions(rules); - // create a new instance of the machine - let tm = TM::new(program, tape); - tm.execute()?; - Ok(()) -} - -pub mod wolfram { - - #[derive( - Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, strum::EnumIter, - )] - #[repr(u8)] - pub enum Three { - #[default] - A = 0, - B = 1, - C = 2, - } - - impl Three { - pub fn as_u8(&self) -> u8 { - *self as u8 - } - - pub fn iter() -> impl Iterator { - use Three::*; - [A, B, C].into_iter() - } - - pub fn iter_value() -> impl Iterator { - [0, 1, 2].into_iter() - } - } - - impl rstm::Alphabet for Three { - type Sym = Self; - - fn to_vec(&self) -> Vec { - use Three::*; - vec![A, B, C] - } - } - - impl IntoIterator for Three { - type Item = Self; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - vec![Three::A, Three::B, Three::C].into_iter() - } - } - - pub enum Two { - A(T), - B(T), - } -} diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index 9266585..ca3dd8e 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -4,10 +4,18 @@ */ //! # rstm //! +//! `rstm` is a Rust library dedicated to the construction and execution of Turing Machines. +//! The crate is designed to be flexible and easy to use while preserving the abstract nature +//! of the models. +//! +//! Actors are one of the primary focuses of the library, designed to essentially mimic the +//! behavior of a smart-contract in reverse. Actors provide an _actionable_ or computable +//! surface for workloads to be executed on. +//! #![crate_name = "rstm"] // #![cfg_attr(not(feature = "std"), no_std)] -// #[cfg(feature = "alloc")] -// extern crate alloc; +#[cfg(feature = "alloc")] +extern crate alloc; pub use rstm_core::*; @@ -15,10 +23,7 @@ pub use rstm_core::*; pub use self::turing::TM; #[macro_use] -pub(crate) mod macros { - #[macro_use] - pub mod rules; -} +pub(crate) mod macros {} pub mod turing; diff --git a/rstm/src/macros/rules.rs b/rstm/src/macros/rules.rs deleted file mode 100644 index 598dedf..0000000 --- a/rstm/src/macros/rules.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* - Appellation: rules - Contrib: FL03 -*/ -/// A macro for creating. -/// -/// # Example -/// -/// ``` -/// -/// use rstm::rule; -/// -/// let rule = rule![(0, '0') -> Right(1, '1')]; -#[macro_export] -macro_rules! rule { - [($state:expr, $symbol:literal $(,)?) -> $direction:ident($next:expr, $write:literal $(,)?) $(,)?] => { - rstm_core::Instruction::new() - .state(rstm_core::State($state)) - .symbol($symbol) - .write_symbol($write) - .direction(rstm_core::Direction::$direction) - .next_state(rstm_core::State($next)) - .build() - }; -} diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 1beed32..13fe0a5 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -51,12 +51,12 @@ impl TM { /// Returns an instance of the [state](State) with an immutable /// reference to the internal data pub fn state(&self) -> State<&'_ Q> { - self.state.view() + self.state.to_ref() } /// Returns an instance of the [state](State) with a mutable /// reference to the internal data pub fn state_mut(&mut self) -> State<&'_ mut Q> { - self.state.view_mut() + self.state.to_mut() } /// Returns an immutable reference to the [tape](StdTape) pub const fn tape(&self) -> &Tape { @@ -100,7 +100,7 @@ impl TM { #[cfg_attr( feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "turing") + tracing::instrument(skip_all, name = "process", target = "turing") )] fn process(&mut self) -> Option> where @@ -114,7 +114,7 @@ impl TM { } // Get the first instruction for the current head if let Some(tail) = self.program.get_head_ref(self.read()?) { - self.state = self.tape.update_inplace(tail.cloned()); + self.state = self.tape.apply_inplace(tail.cloned()); return self.read(); } unreachable!("No instruction found for the current head") diff --git a/rstm/tests/actor.rs b/rstm/tests/actor.rs deleted file mode 100644 index 6ea6f81..0000000 --- a/rstm/tests/actor.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - Appellation: actor - Contrib: FL03 -*/ - -use lazy_static::lazy_static; -use rstm::actors::Actor; -use rstm::{rule, Program, State}; - -lazy_static! { - static ref ALPHA: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; - static ref RULES: Program = Program::from_iter([ - rule![(0, 0) -> Right(0, 0)], - rule![(0, 1) -> Right(1, 0)], - rule![(1, 0) -> Right(0, 1)], - rule![(1, 1) -> Left(1, 0)], - rule![(-1, 0) -> Right(0, 1)], - rule![(-1, 1) -> Stay(0, 0)], - ]); -} - -#[should_panic] -#[test] -fn test_actor() { - let input = [0_usize; 10]; - - let actor = Actor::new().alpha(input).state(State(0)).build(); - actor.exec(RULES.clone()); -} From ba4b320a0b4661ca2da5b865bc06267eb150640a Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 16 Aug 2024 12:31:48 -0500 Subject: [PATCH 24/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 2 +- core/src/actors/exec.rs | 5 +- core/src/rules/builders/program.rs | 43 +++++++++++++++++ core/src/rules/builders/rule.rs | 77 ++++++++++++++++++++++++++++++ core/src/rules/entry.rs | 24 ---------- core/src/rules/mod.rs | 14 +++++- core/src/rules/program.rs | 46 ++++++++---------- core/src/rules/rule.rs | 77 +----------------------------- core/tests/actor.rs | 5 +- rstm/examples/actor.rs | 5 +- rstm/examples/basic.rs | 4 +- 11 files changed, 165 insertions(+), 137 deletions(-) create mode 100644 core/src/rules/builders/program.rs create mode 100644 core/src/rules/builders/rule.rs delete mode 100644 core/src/rules/entry.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index c6c01c5..55dc690 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -119,7 +119,7 @@ impl Actor { mod builder { use super::*; - use std::iter::FromIterator; + use core::iter::FromIterator; #[derive(Default)] pub struct ActorBuilder { diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 6df30d6..b60ee0c 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -20,7 +20,10 @@ impl Executor { { Self { actor, - program: Program::new(), + program: Program { + initial_state: Default::default(), + rules: Vec::new(), + }, } } diff --git a/core/src/rules/builders/program.rs b/core/src/rules/builders/program.rs new file mode 100644 index 0000000..698549a --- /dev/null +++ b/core/src/rules/builders/program.rs @@ -0,0 +1,43 @@ +/* + Appellation: builder + Contrib: FL03 +*/ +use crate::rules::{Program, Rule}; +use crate::State; +pub struct ProgramBuilder { + initial_state: Option>, + rules: Vec>, +} + +impl ProgramBuilder { + pub fn new() -> Self { + Self { + initial_state: None, + rules: Vec::new(), + } + } + + pub fn initial_state(self, State(state): State) -> Self { + Self { + initial_state: Some(State(state)), + ..self + } + } + + pub fn rules(self, rules: I) -> Self + where + I: IntoIterator>, + { + Self { + rules: Vec::from_iter(rules), + ..self + } + } + + pub fn build(self) -> Program { + Program { + initial_state: self.initial_state.unwrap(), + rules: self.rules, + } + } +} diff --git a/core/src/rules/builders/rule.rs b/core/src/rules/builders/rule.rs new file mode 100644 index 0000000..439fddc --- /dev/null +++ b/core/src/rules/builders/rule.rs @@ -0,0 +1,77 @@ +/* + Appellation: rule + Contrib: FL03 +*/ +use crate::rules::Rule; +use crate::{Direction, State}; + +#[derive(Default)] +pub struct RuleBuilder { + direction: Direction, + state: Option>, + symbol: Option, + next_state: Option>, + write_symbol: Option, +} + +impl RuleBuilder { + 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) -> Rule { + Rule { + head: crate::Head { + state: self.state.expect("state is required"), + symbol: self.symbol.expect("symbol is required"), + }, + tail: crate::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/core/src/rules/entry.rs b/core/src/rules/entry.rs deleted file mode 100644 index 5786e12..0000000 --- a/core/src/rules/entry.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* - Appellation: entry - Contrib: FL03 -*/ -pub use crate::{Head, Tail}; - -pub struct Entry<'a, Q, S> { - key: &'a mut Head, - value: &'a mut Tail, -} - -impl<'a, Q, S> Entry<'a, Q, S> { - pub fn new(key: &'a mut Head, value: &'a mut Tail) -> Self { - Self { key, value } - } - - pub fn key(&self) -> &Head { - &self.key - } - - pub fn value(&self) -> &Tail { - &self.value - } -} diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 9421546..d92edd1 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -3,17 +3,27 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{program::*, rule::*}; +pub use self::{ + builders::{ProgramBuilder, RuleBuilder}, + program::Program, + rule::Rule, +}; pub(crate) mod program; pub(crate) mod rule; #[doc(hidden)] -pub mod entry; +pub(crate) mod builders { + pub use self::{program::ProgramBuilder, rule::RuleBuilder}; + + mod program; + mod rule; +} pub(crate) mod prelude { pub use super::program::Program; pub use super::rule::Rule; + pub use super::{Directive, Scope, Transition}; } use crate::{Direction, State, Symbolic}; diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 6f3c0a8..8209282 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -2,7 +2,7 @@ Appellation: program Contrib: FL03 */ -use super::Rule; +use super::{ProgramBuilder, Rule}; use crate::{Head, State, Tail}; use std::vec; @@ -13,19 +13,13 @@ type Ruleset = Vec>; #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Program { - pub initial_state: State, - pub(crate) ruleset: Ruleset, + pub(crate) initial_state: State, + pub(crate) rules: Ruleset, } impl Program { - pub fn new() -> Self - where - Q: Default, - { - Self { - initial_state: State::default(), - ruleset: Vec::new(), - } + pub fn new() -> ProgramBuilder { + ProgramBuilder::new() } pub fn from_iter(instructions: impl IntoIterator>) -> Self @@ -34,14 +28,14 @@ impl Program { { Self { initial_state: State::default(), - ruleset: Ruleset::from_iter(instructions), + rules: Ruleset::from_iter(instructions), } } pub fn from_state(State(initial_state): State) -> Self { Self { initial_state: State(initial_state), - ruleset: Ruleset::new(), + rules: Ruleset::new(), } } /// @@ -54,7 +48,7 @@ impl Program { /// pub fn with_instructions(self, instructions: impl IntoIterator>) -> Self { Self { - ruleset: Ruleset::from_iter(instructions), + rules: Ruleset::from_iter(instructions), ..self } } @@ -64,19 +58,19 @@ impl Program { } /// Returns a reference to the instructions. pub const fn instructions(&self) -> &Ruleset { - &self.ruleset + &self.rules } /// Returns a mutable reference to the instructions. pub fn instructions_mut(&mut self) -> &mut Ruleset { - &mut self.ruleset + &mut self.rules } /// Returns an iterator over the elements. pub fn iter(&self) -> core::slice::Iter> { - self.ruleset.iter() + self.rules.iter() } /// Returns a mutable iterator over the elements. pub fn iter_mut(&mut self) -> core::slice::IterMut> { - self.ruleset.iter_mut() + self.rules.iter_mut() } pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> @@ -138,13 +132,13 @@ impl Program { impl AsRef<[Rule]> for Program { fn as_ref(&self) -> &[Rule] { - &self.ruleset + &self.rules } } impl AsMut<[Rule]> for Program { fn as_mut(&mut self) -> &mut [Rule] { - &mut self.ruleset + &mut self.rules } } @@ -152,13 +146,13 @@ impl core::ops::Deref for Program { type Target = [Rule]; fn deref(&self) -> &Self::Target { - &self.ruleset + &self.rules } } impl core::ops::DerefMut for Program { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.ruleset + &mut self.rules } } @@ -178,14 +172,14 @@ impl From> for Program { fn from(instructions: Ruleset) -> Self { Self { initial_state: State::default(), - ruleset: instructions, + rules: instructions, } } } impl Extend> for Program { fn extend>>(&mut self, iter: I) { - self.ruleset.extend(iter) + self.rules.extend(iter) } } @@ -196,7 +190,7 @@ where fn from_iter>>(iter: I) -> Self { Self { initial_state: State::default(), - ruleset: Ruleset::from_iter(iter), + rules: Ruleset::from_iter(iter), } } } @@ -206,6 +200,6 @@ impl IntoIterator for Program { type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.ruleset.into_iter() + self.rules.into_iter() } } diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 75320cc..d1a3e20 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -2,7 +2,7 @@ Appellation: instruction Contrib: FL03 */ -pub use self::builder::RuleBuilder; +use super::RuleBuilder; use crate::prelude::{Direction, Head, State, Tail}; @@ -65,78 +65,3 @@ impl Rule { self.tail().write_symbol() } } - -mod builder { - use super::*; - - #[derive(Default)] - pub struct RuleBuilder { - direction: Direction, - state: Option>, - symbol: Option, - next_state: Option>, - write_symbol: Option, - } - - impl RuleBuilder { - 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) -> Rule { - Rule { - 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/core/tests/actor.rs b/core/tests/actor.rs index cefd017..192aed6 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -28,8 +28,9 @@ fn test_actor() { let input = [0_usize; 10]; let program = Program::new() - .with_instructions(RULES.clone()) - .with_initial_state(INITIAL_STATE); + .rules(RULES.clone()) + .initial_state(INITIAL_STATE) + .build(); let actor = Actor::new().alpha(input).state(State(0)).build(); assert!(actor.execute(program).run().is_ok()); diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index e536871..efebc06 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -23,8 +23,9 @@ fn main() -> Result<(), Box> { ]; let program = Program::new() - .with_initial_state(initial_state) - .with_instructions(rules); + .initial_state(initial_state) + .rules(rules) + .build(); // create a new instance of the machine let tm = dbg!(Actor::new().alpha(alpha).state(initial_state).build()); diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 4a8cb5b..750cd34 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -32,9 +32,7 @@ fn main() -> Result<(), Box> { (-1, 1) -> Stay(0, 0), ]; // create a new program with the rules - let program = Program::new() - .with_instructions(rules) - .with_initial_state(State(0)); + let program = Program::new().initial_state(State(0)).rules(rules).build(); // create a new tape with the data let tape = Tape::from_iter(alpha); // create a new instance of the machine From ff97712beb0e16c28bad5f03110143fb07b5c35a Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 16 Aug 2024 14:04:00 -0500 Subject: [PATCH 25/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 64 ++++++++++++++++++++++++++++++++++++---- core/src/actors/exec.rs | 30 +++++++++++-------- rstm/examples/actor.rs | 12 ++++---- rstm/examples/basic.rs | 23 ++++----------- rstm/src/turing.rs | 2 +- 5 files changed, 90 insertions(+), 41 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 55dc690..a9afbe0 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -10,7 +10,7 @@ use crate::rules::{Directive, Program}; use crate::{Head, State}; /// An [Actor] describes a Turing machine with a moving head (TMH). -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Actor { /// the input alphabet pub(crate) alpha: Vec, @@ -24,12 +24,16 @@ impl Actor { } pub fn from_state(State(state): State) -> ActorBuilder { - ActorBuilder::from_state(State(state)) + ActorBuilder::new().state(State(state)) } /// Returns an immutable reference to the tape alphabet as a slice pub fn alpha(&self) -> &[S] { &self.alpha } + + pub fn cursor(&self) -> usize { + self.head.symbol + } /// Returns an immutable reference to the head of the tape pub const fn head(&self) -> &Head { &self.head @@ -95,7 +99,7 @@ impl Actor { )] pub fn read(&self) -> Option> { #[cfg(feature = "tracing")] - tracing::info!("Reading the tape..."); + tracing::debug!("Reading the tape..."); let Head { state, symbol } = self.head_ref(); self.alpha.get(symbol).map(|value| Head::new(state, value)) } @@ -106,15 +110,65 @@ impl Actor { )] pub fn write(&mut self, value: S) { let pos = self.head.symbol; - if pos < self.len() { + if self.cursor() < self.len() { self.alpha[pos] = value; } else { #[cfg(feature = "tracing")] - tracing::info!("Appending to the tape..."); + tracing::debug!("Appending to the tape..."); // append to the tape self.alpha.push(value); } } + + pub fn print(&self) -> String + where + S: core::fmt::Display, + { + self.alpha + .iter() + .enumerate() + .map(|(i, c)| { + let c = c.to_string(); + if i == self.cursor() { + format!("[{c}]") + } else { + format!("{c}") + } + }) + .collect::() + } +} + +impl core::fmt::Debug for Actor +where + Q: core::fmt::Debug, + S: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + for (i, c) in self.alpha.iter().enumerate() { + match c { + b if i == self.cursor() => write!(f, "[{:?}, {b:?}]", self.head.state)?, + _ => write!(f, "{c:?}")?, + } + } + Ok(()) + } +} + +impl core::fmt::Display for Actor +where + Q: core::fmt::Display, + S: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + for (i, c) in self.alpha.iter().enumerate() { + match c { + b if i == self.cursor() => write!(f, "[{}, {b}]", self.head.state)?, + _ => write!(f, "{c}")?, + } + } + Ok(()) + } } mod builder { diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index b60ee0c..7633047 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -30,13 +30,14 @@ impl Executor { pub fn with_program(self, program: Program) -> Self { Executor { program, ..self } } + #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "run", target = "actor") )] pub fn run(&mut self) -> Result, Error> where - Q: Clone + PartialEq + 'static, + Q: Clone + PartialEq + core::fmt::Debug + 'static, S: Symbolic, { #[cfg(feature = "tracing")] @@ -44,13 +45,7 @@ impl Executor { loop { match self.next() { Some(_) => continue, - None => { - if self.actor.is_halted() { - break; - } else { - return Err(Error::runtime_error("Unknown Error".to_string())); - } - } + None => break, } } Ok(self.actor.alpha().to_vec()) @@ -59,7 +54,7 @@ impl Executor { impl Iterator for Executor where - Q: Clone + PartialEq + 'static, + Q: Clone + PartialEq + core::fmt::Debug + 'static, S: Symbolic, { type Item = Head; @@ -74,8 +69,19 @@ where tracing::info!("Halted"); return None; } - let Head { state, symbol } = self.actor.read()?; - let rule = self.program.get(state, symbol)?; - self.actor.step(rule).map(|h| h.cloned()) + match self.actor.read() { + Some(Head { state, symbol }) => { + #[cfg(feature = "tracing")] + tracing::info!("{tape:?}", tape = self.actor); + let rule = self.program.get(state, symbol).expect("No instruction found for the current head"); + return self.actor.step(rule).map(|h| h.cloned()); + } + None => { + #[cfg(feature = "tracing")] + tracing::error!("No instruction found for the current head"); + panic!("No head found at the current position"); + } + } + } } diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index efebc06..670b4fe 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -14,12 +14,12 @@ fn main() -> Result<(), Box> { let initial_state = State(0); // define the ruleset for the machine let rules = ruleset![ - (0, 0) -> Right(0, 0), - (0, 1) -> Right(1, 0), + (0, 0) -> Right(1, 0), + (0, 1) -> Right(-1, 1), (1, 0) -> Right(0, 1), - (1, 1) -> Left(1, 0), - (-1, 0) -> Right(0, 1), - (-1, 1) -> Stay(0, 0), + (1, 1) -> Right(-1, 0), + (-1, 0) -> Left(0, 0), + (-1, 1) -> Left(1, 1), ]; let program = Program::new() @@ -37,7 +37,7 @@ fn main() -> Result<(), Box> { fn _tracing() { let timer = tracing_subscriber::fmt::time::uptime(); tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) + .with_max_level(tracing::Level::TRACE) .with_target(false) .with_timer(timer) .init(); diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 750cd34..31bb439 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -6,17 +6,6 @@ extern crate rstm; use rstm::{ruleset, Program, State, Tape, TM}; -lazy_static::lazy_static! { - static ref RULES: Program = Program::from_iter(ruleset![ - (0, 0) -> Right(0, 1), - (0, 1) -> Right(1, 0), - (1, 0) -> Right(-1, 1), - (1, 1) -> Left(1, 0), - (-1, 0) -> Right(0, 1), - (-1, 1) -> Stay(0, 0), - ]); -} - fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); @@ -24,12 +13,12 @@ fn main() -> Result<(), Box> { let alpha = [0_usize; 10]; // define the rules for the machine let rules = ruleset![ - (0, 0) -> Right(0, 1), - (0, 1) -> Right(1, 0), - (1, 0) -> Right(-1, 1), - (1, 1) -> Left(1, 0), - (-1, 0) -> Right(0, 1), - (-1, 1) -> Stay(0, 0), + (0, 0) -> Right(1, 0), + (0, 1) -> Right(-1, 1), + (1, 0) -> Right(0, 1), + (1, 1) -> Right(-1, 0), + (-1, 0) -> Left(0, 0), + (-1, 1) -> Left(1, 1), ]; // create a new program with the rules let program = Program::new().initial_state(State(0)).rules(rules).build(); diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 13fe0a5..4ea68b3 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -92,7 +92,7 @@ impl TM { } } None => { - return Err(Error::unknown("Runtime Error")); + return Err(Error::runtime_error("")); } } } From 97558443106593d4bbd39c9a56668488817dc3b4 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 07:42:24 -0500 Subject: [PATCH 26/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 38 +++++++----------- core/src/types/head.rs | 84 ++++++++++++++++++++++++++++++++++------ rstm/src/turing.rs | 6 +-- 3 files changed, 89 insertions(+), 39 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index a9afbe0..3f60c5e 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -10,7 +10,9 @@ use crate::rules::{Directive, Program}; use crate::{Head, State}; /// An [Actor] describes a Turing machine with a moving head (TMH). -#[derive(Clone)] +/// +/// [Actor]'s abstractly define actionable surfaces capable of executing a [Program]. +#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd)] pub struct Actor { /// the input alphabet pub(crate) alpha: Vec, @@ -67,6 +69,8 @@ impl Actor { D: Directive, S: Clone, { + #[cfg(feature = "tracing")] + tracing::debug!("Stepping the tape..."); self.write(rule.value().clone()); self.head.shift_inplace(rule.direction()); self.read() @@ -119,24 +123,6 @@ impl Actor { self.alpha.push(value); } } - - pub fn print(&self) -> String - where - S: core::fmt::Display, - { - self.alpha - .iter() - .enumerate() - .map(|(i, c)| { - let c = c.to_string(); - if i == self.cursor() { - format!("[{c}]") - } else { - format!("{c}") - } - }) - .collect::() - } } impl core::fmt::Debug for Actor @@ -146,9 +132,10 @@ where { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for (i, c) in self.alpha.iter().enumerate() { - match c { - b if i == self.cursor() => write!(f, "[{:?}, {b:?}]", self.head.state)?, - _ => write!(f, "{c:?}")?, + if i == self.cursor() { + write!(f, "[{c:?}]")?; + } else { + write!(f, "{c:?}")?; } } Ok(()) @@ -162,9 +149,10 @@ where { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for (i, c) in self.alpha.iter().enumerate() { - match c { - b if i == self.cursor() => write!(f, "[{}, {b}]", self.head.state)?, - _ => write!(f, "{c}")?, + if i == self.cursor() { + write!(f, "[{c}]")?; + } else { + write!(f, "{c}")?; } } Ok(()) diff --git a/core/src/types/head.rs b/core/src/types/head.rs index a2e2647..a4ec56c 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -4,24 +4,23 @@ */ 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::Tape). +/// The [Head] struct represent the state and symbol of an actor at a given moment in time. +/// With respect to a Turing machine, the head defines the current state and symbol of the +/// machine. When associated with a direction the head becomes a tail, instructing the machine +/// to move, write, and transition to a new state. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(rename_all = "lowercase"))] pub struct Head { #[cfg_attr( feature = "serde", serde( - flatten, - alias = "state", - alias = "current_state", - alias = "head_state" + alias = "current_state" ) )] pub state: State, #[cfg_attr( feature = "serde", - serde(flatten, alias = "symbol", alias = "current_symbol", alias = "value") + serde(flatten, alias = "current_symbol") )] pub symbol: S, } @@ -45,7 +44,6 @@ impl Head { 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; @@ -79,7 +77,7 @@ impl Head { self.symbol = symbol; } } - + /// Converts the current head into a new head with immutable references to the current state and symbol pub fn to_ref<'a>(&'a self) -> Head<&Q, &S> where Q: 'a, @@ -90,7 +88,7 @@ impl Head { symbol: &self.symbol, } } - + /// Converts the current head into a new head with mutable references to the current state and symbol pub fn to_mut<'a>(&'a mut self) -> Head<&mut Q, &mut S> where Q: 'a, @@ -104,6 +102,10 @@ impl Head { } impl Head { + pub fn read_tape<'a, S>(&self, tape: &'a [S]) -> Option<&'a S> { + tape.get(self.symbol) + } + pub fn shift(self, direction: crate::Direction) -> Self { Self { symbol: direction.apply(self.symbol), @@ -127,8 +129,68 @@ impl<'a, Q, S> Head<&'a Q, &'a S> { symbol: self.symbol.clone(), } } + + pub fn copied(&self) -> Head + where + Q: Copy, + S: Copy, + { + Head { + state: self.state.copied(), + symbol: self.symbol.clone(), + } + } +} + +impl<'a, Q, S> Head<&'a mut Q, &'a mut S> { + pub fn cloned(&self) -> Head + where + Q: Clone, + S: Clone, + { + Head { + state: self.state.cloned(), + symbol: self.symbol.clone(), + } + } + + pub fn copied(&self) -> Head + where + Q: Copy, + S: Copy, + { + Head { + state: self.state.copied(), + symbol: *self.symbol, + } + } } +impl<'a, Q, S> Head<*const Q, *const S> { + pub fn cloned(&self) -> Head<*const Q, *const S> + where + Q: Clone, + S: Clone, + { + Head { + state: self.state.clone(), + symbol: self.symbol.clone(), + } + } + + pub unsafe fn copied(&self) -> Head + where + Q: Copy, + S: Copy, + { + Head { + state: State(*self.state.0), + symbol: *self.symbol, + } + } +} + + impl From<(Q, S)> for Head { fn from((state, symbol): (Q, S)) -> Self { Self::new(State(state), symbol) diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 4ea68b3..ac1f0fd 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -7,7 +7,7 @@ pub use self::{model::Turing, state::TMS}; pub(crate) mod model; pub(crate) mod state; -use crate::prelude::{Error, Head, Symbolic, Tape}; +use crate::prelude::{Error, Head, Symbolic, Tail, Tape}; use crate::rules::Program; use crate::state::State; @@ -113,8 +113,8 @@ impl TM { return None; } // Get the first instruction for the current head - if let Some(tail) = self.program.get_head_ref(self.read()?) { - self.state = self.tape.apply_inplace(tail.cloned()); + if let Some(Tail { direction, state, symbol }) = self.program.get_head_ref(self.read()?).map(|tail| tail.cloned()) { + self.state = self.tape.update_inplace(direction, state, symbol); return self.read(); } unreachable!("No instruction found for the current head") From 09f9dc87c317ea3af2c201b445ade162d0b0ffb7 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 12:57:17 -0500 Subject: [PATCH 27/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 52 +++++++++++++++++++++++----------------- core/src/actors/exec.rs | 39 ++++++++++++++++-------------- core/src/types/head.rs | 25 ++++++++----------- rstm/examples/actor.rs | 2 +- rstm/src/turing.rs | 10 +++++++- 5 files changed, 71 insertions(+), 57 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 3f60c5e..574bc5c 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -6,11 +6,11 @@ pub use self::builder::ActorBuilder; use super::Executor; -use crate::rules::{Directive, Program}; -use crate::{Head, State}; +use crate::rules::Program; +use crate::{Direction, Head, State}; /// An [Actor] describes a Turing machine with a moving head (TMH). -/// +/// /// [Actor]'s abstractly define actionable surfaces capable of executing a [Program]. #[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd)] pub struct Actor { @@ -59,22 +59,7 @@ impl Actor { pub fn state_mut(&mut self) -> State<&mut Q> { self.head.state_mut() } - /// Performs a single step of the Turing machine - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "actor") - )] - pub fn step(&mut self, rule: &D) -> Option> - where - D: Directive, - S: Clone, - { - #[cfg(feature = "tracing")] - tracing::debug!("Stepping the tape..."); - self.write(rule.value().clone()); - self.head.shift_inplace(rule.direction()); - self.read() - } + /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. pub fn execute(self, program: Program) -> Executor { @@ -113,16 +98,39 @@ impl Actor { tracing::instrument(skip_all, name = "write", target = "actor") )] pub fn write(&mut self, value: S) { + #[cfg(feature = "tracing")] + tracing::debug!("Writing to the tape..."); let pos = self.head.symbol; - if self.cursor() < self.len() { - self.alpha[pos] = value; - } else { + if pos >= self.len() { #[cfg(feature = "tracing")] tracing::debug!("Appending to the tape..."); // append to the tape self.alpha.push(value); + } else { + self.alpha[pos] = value; } } + /// Performs a single step of the Turing machine + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "step", target = "actor") + )] + pub fn step( + &mut self, + direction: Direction, + State(state): State, + symbol: S, + ) -> Option> + where + S: Clone, + { + #[cfg(feature = "tracing")] + tracing::debug!("Stepping the tape..."); + self.write(symbol); + self.head.set_state(State(state)); + self.head.shift_inplace(direction); + self.read() + } } impl core::fmt::Debug for Actor diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 7633047..40d13dd 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -42,11 +42,8 @@ impl Executor { { #[cfg(feature = "tracing")] tracing::info!("Executing the program using the given actor..."); - loop { - match self.next() { - Some(_) => continue, - None => break, - } + while let Some(_) = self.next() { + continue; } Ok(self.actor.alpha().to_vec()) } @@ -69,19 +66,25 @@ where tracing::info!("Halted"); return None; } - match self.actor.read() { - Some(Head { state, symbol }) => { - #[cfg(feature = "tracing")] - tracing::info!("{tape:?}", tape = self.actor); - let rule = self.program.get(state, symbol).expect("No instruction found for the current head"); - return self.actor.step(rule).map(|h| h.cloned()); - } - None => { - #[cfg(feature = "tracing")] - tracing::error!("No instruction found for the current head"); - panic!("No head found at the current position"); - } + if let Some(head) = self.actor.read() { + #[cfg(feature = "tracing")] + tracing::info!("{tape:?}", tape = self.actor); + let crate::Tail { + direction, + state, + symbol, + } = self + .program + .get_head_ref(head) + .expect("No instruction found for the current head"); + return self + .actor + .step(direction, state.cloned(), *symbol) + .map(|h| h.cloned()); + } else { + #[cfg(feature = "tracing")] + tracing::error!("No instruction found for the current head"); + panic!("No head found at the current position"); } - } } diff --git a/core/src/types/head.rs b/core/src/types/head.rs index a4ec56c..ef4ad98 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -4,24 +4,20 @@ */ use crate::state::State; -/// The [Head] struct represent the state and symbol of an actor at a given moment in time. -/// With respect to a Turing machine, the head defines the current state and symbol of the +/// The [Head] struct represent the state and symbol of an actor at a given moment in time. +/// With respect to a Turing machine, the head defines the current state and symbol of the /// machine. When associated with a direction the head becomes a tail, instructing the machine /// to move, write, and transition to a new state. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(rename_all = "lowercase"))] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "lowercase") +)] pub struct Head { - #[cfg_attr( - feature = "serde", - serde( - alias = "current_state" - ) - )] + #[cfg_attr(feature = "serde", serde(alias = "current_state"))] pub state: State, - #[cfg_attr( - feature = "serde", - serde(flatten, alias = "current_symbol") - )] + #[cfg_attr(feature = "serde", serde(flatten, alias = "current_symbol"))] pub symbol: S, } @@ -105,7 +101,7 @@ impl Head { pub fn read_tape<'a, S>(&self, tape: &'a [S]) -> Option<&'a S> { tape.get(self.symbol) } - + pub fn shift(self, direction: crate::Direction) -> Self { Self { symbol: direction.apply(self.symbol), @@ -190,7 +186,6 @@ impl<'a, Q, S> Head<*const Q, *const S> { } } - impl From<(Q, S)> for Head { fn from((state, symbol): (Q, S)) -> Self { Self::new(State(state), symbol) diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 670b4fe..7254709 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -30,7 +30,7 @@ fn main() -> Result<(), Box> { // create a new instance of the machine let tm = dbg!(Actor::new().alpha(alpha).state(initial_state).build()); let out = tm.execute(program).run()?; - println!("{out:?}"); + println!("Output: {out:?}"); Ok(()) } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index ac1f0fd..2905fa4 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -113,7 +113,15 @@ impl TM { return None; } // Get the first instruction for the current head - if let Some(Tail { direction, state, symbol }) = self.program.get_head_ref(self.read()?).map(|tail| tail.cloned()) { + if let Some(Tail { + direction, + state, + symbol, + }) = self + .program + .get_head_ref(self.read()?) + .map(|tail| tail.cloned()) + { self.state = self.tape.update_inplace(direction, state, symbol); return self.read(); } From d4d8ec3d06872670c30fb4828335fc4e668334d1 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 14:56:12 -0500 Subject: [PATCH 28/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 9 ++--- core/src/tape/mod.rs | 7 ++++ core/src/traits/cspace.rs | 8 ++++- core/src/traits/io.rs | 2 ++ core/src/traits/mod.rs | 1 - core/src/traits/symbolic.rs | 65 +++++++++++++++++++++++++++++++------ core/src/types/head.rs | 32 ++++++++++++++++++ 7 files changed, 108 insertions(+), 16 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 574bc5c..501b45a 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -51,15 +51,14 @@ impl Actor { pub fn head_mut(&mut self) -> &mut Head { &mut self.head } - /// Returns the current state of the tape + /// Returns an instance of the state with an immutable reference to the inner value pub fn state(&self) -> State<&Q> { self.head.state() } - /// Returns a mutable reference to the current state of the tape + /// Returns an instance of the state with a mutable reference to the inner value pub fn state_mut(&mut self) -> State<&mut Q> { self.head.state_mut() } - /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. pub fn execute(self, program: Program) -> Executor { @@ -115,7 +114,7 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "step", target = "actor") )] - pub fn step( + pub(crate) fn step( &mut self, direction: Direction, State(state): State, @@ -127,7 +126,9 @@ impl Actor { #[cfg(feature = "tracing")] tracing::debug!("Stepping the tape..."); self.write(symbol); + // set the state of the head self.head.set_state(State(state)); + // shift the head in the given direction self.head.shift_inplace(direction); self.read() } diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 8a862bb..ab569a4 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -25,6 +25,13 @@ pub trait RawTape { fn as_slice(&self) -> &[Self::Elem]; } +#[doc(hidden)] +pub trait Reader { + type Output; + + fn read(&self) -> Self::Output; +} + /* ************* Implementations ************* */ diff --git a/core/src/traits/cspace.rs b/core/src/traits/cspace.rs index 31af39b..c78b063 100644 --- a/core/src/traits/cspace.rs +++ b/core/src/traits/cspace.rs @@ -3,12 +3,18 @@ Contrib: FL03 */ +pub trait Point { + type Elem; +} + pub trait RawSpace { type Elem; - fn space(&self) -> Self::Elem; + private!(); } +pub trait Space: RawSpace {} + pub trait ConfigSpace { type Space; } diff --git a/core/src/traits/io.rs b/core/src/traits/io.rs index d04a1f6..9e1a52f 100644 --- a/core/src/traits/io.rs +++ b/core/src/traits/io.rs @@ -6,7 +6,9 @@ pub trait RawBuf { type Elem; + /// Returns an immutable reference to the buffer as a slice fn as_slice(&self) -> &[Self::Elem]; + /// Returns a mutable reference to the buffer as a slice fn as_mut_slice(&mut self) -> &mut [Self::Elem]; } diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index bcd5904..e1caf7c 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -13,5 +13,4 @@ pub mod symbolic; pub(crate) mod prelude { pub use super::symbolic::*; - // pub use super::transform::*; } diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index d6f2070..9b468c9 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -3,12 +3,7 @@ Contrib: FL03 */ -/// [Alphabet] abstractly describes the set of symbols used for both -/// the input and output of any given Turing machine. -/// -/// ### Definition -/// -/// An alphabet is formally defines to be a finite set of symbols. +/// [Alphabet] describes a finite set of symbols used to construct a formal language. /// /// Ideally, the alphabet should be implemented on unit enums since /// each symbol can be represented as a unique variant and assigned @@ -16,13 +11,21 @@ /// as pointers, specifiying the location of the symbol w.r.t. the /// alphabet. pub trait Alphabet { - type Sym; + type Elem; + + fn as_slice(&self) -> &[Self::Elem]; + + fn as_mut_slice(&mut self) -> &mut [Self::Elem]; + + fn is_empty(&self) -> bool { + self.as_slice().is_empty() + } fn len(&self) -> usize { - self.to_vec().len() + self.as_slice().len() } - fn to_vec(&self) -> Vec; + fn to_vec(&self) -> Vec; } /// [Symbolic] is a trait denoting types that can be used as symbols; @@ -48,9 +51,51 @@ where /* ************* Implementations ************* */ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +impl Alphabet for [S] { + type Elem = S; + + fn as_slice(&self) -> &[S] { + self + } + + fn as_mut_slice(&mut self) -> &mut [S] { + self + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn len(&self) -> usize { + self.len() + } + + fn to_vec(&self) -> Vec { + self.to_vec() + } +} impl Alphabet for Vec { - type Sym = S; + type Elem = S; + + fn as_slice(&self) -> &[S] { + self.as_slice() + } + + fn as_mut_slice(&mut self) -> &mut [S] { + self.as_mut_slice() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn len(&self) -> usize { + self.len() + } fn to_vec(&self) -> Vec { self.clone() diff --git a/core/src/types/head.rs b/core/src/types/head.rs index ef4ad98..00e167a 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -28,6 +28,38 @@ impl Head { symbol, } } + /// Create a new instance of the [Head] using the given state and default symbol. + pub fn from_state(State(state): State) -> Self where S: Default { + Self { + state: State(state), + symbol: Default::default(), + } + } + /// Create a new instance of the [Head] using the given symbol and default state. + pub fn from_symbol(symbol: S) -> Self where Q: Default { + Self { + state: Default::default(), + symbol, + } + } + /// Create a new instance from a 2-tuple: ([state](State), symbol) + pub fn from_tuple((state, symbol): (State, S)) -> Self { + Self { + state, + symbol, + } + } + /// Updates the current [state](State) and returns a new head + pub fn with_state(self, State(state): State) -> Self { + Self { + state: State(state), + ..self + } + } + /// Updates the current symbol and returns a new head + pub fn with_symbol(self, symbol: S) -> Self { + Self { symbol, ..self } + } /// 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) From 7a4ac4bafba6ed0de9a7cf5902891fcc2869797c Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 15:13:55 -0500 Subject: [PATCH 29/35] update Signed-off-by: Joe McCain III --- core/src/state/halt/mod.rs | 23 +++++++ .../{states/halting.rs => halt/state.rs} | 11 +-- core/src/state/halt/wrap.rs | 69 +++++++++++++++++++ core/src/state/mod.rs | 7 +- core/src/types/head.rs | 15 ++-- 5 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 core/src/state/halt/mod.rs rename core/src/state/{states/halting.rs => halt/state.rs} (92%) create mode 100644 core/src/state/halt/wrap.rs diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs new file mode 100644 index 0000000..76dc125 --- /dev/null +++ b/core/src/state/halt/mod.rs @@ -0,0 +1,23 @@ +/* + Appellation: halt + Contrib: FL03 +*/ +//! This module is responsible for defining the [Halt] state of a Turing machine. +//! +//! +#[doc(inline)] +pub use self::{state::Halt, wrap::Halting}; + +pub(crate) mod state; +pub(crate) mod wrap; + +use crate::state::RawState; + +#[doc(hidden)] +pub trait Haltable { + const HALT: bool = true; + + type State: RawState; + + private!(); +} diff --git a/core/src/state/states/halting.rs b/core/src/state/halt/state.rs similarity index 92% rename from core/src/state/states/halting.rs rename to core/src/state/halt/state.rs index 979c709..e87033b 100644 --- a/core/src/state/states/halting.rs +++ b/core/src/state/halt/state.rs @@ -2,16 +2,7 @@ Appellation: halting Contrib: FL03 */ -use crate::state::{RawState, State}; - -#[doc(hidden)] -pub trait Haltable { - const HALT: bool = true; - - type State: RawState; - - private!(); -} +use crate::state::{halt::Haltable, State}; #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] diff --git a/core/src/state/halt/wrap.rs b/core/src/state/halt/wrap.rs new file mode 100644 index 0000000..31146b1 --- /dev/null +++ b/core/src/state/halt/wrap.rs @@ -0,0 +1,69 @@ +/* + Appellation: wrap + Contrib: FL03 +*/ +use crate::state::{Halt, State}; + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum Halting { + Step(State), + Halt(Halt), +} + +impl Halting { + pub fn is_halted(&self) -> bool { + match self { + Self::Halt(_) => true, + _ => false, + } + } + + pub fn is_continuing(&self) -> bool { + match self { + Self::Step(_) => true, + _ => false, + } + } + + pub fn into_state(self) -> State { + match self { + Self::Step(state) => state, + Self::Halt(halt) => State(halt.0), + } + } + + pub fn as_state(&self) -> State<&Q> { + match self { + Self::Step(state) => state.to_ref(), + Self::Halt(halt) => State(halt.view().0), + } + } + + pub fn get(&self) -> &Q { + match self { + Self::Step(inner) => inner.get(), + Self::Halt(inner) => inner.get(), + } + } + + pub fn get_mut(&mut self) -> &mut Q { + match self { + Self::Step(inner) => inner.get_mut(), + Self::Halt(inner) => inner.get_mut(), + } + } + + pub fn set(&mut self, state: Q) { + match self { + Self::Step(inner) => inner.set(state), + Self::Halt(inner) => inner.set(state), + } + } +} + +impl Default for Halting { + fn default() -> Self { + Self::Step(State::default()) + } +} diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 69dba89..24f8460 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -3,16 +3,17 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{state::State, states::*}; +pub use self::{halt::Halt, state::State, states::*}; pub(crate) mod state; +pub mod halt; + pub(crate) mod states { #[doc(inline)] - pub use self::{binary::*, halting::*}; + pub use self::binary::*; pub(crate) mod binary; - pub(crate) mod halting; } pub(crate) mod prelude { diff --git a/core/src/types/head.rs b/core/src/types/head.rs index 00e167a..a820512 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -29,14 +29,20 @@ impl Head { } } /// Create a new instance of the [Head] using the given state and default symbol. - pub fn from_state(State(state): State) -> Self where S: Default { + pub fn from_state(State(state): State) -> Self + where + S: Default, + { Self { state: State(state), symbol: Default::default(), } } /// Create a new instance of the [Head] using the given symbol and default state. - pub fn from_symbol(symbol: S) -> Self where Q: Default { + pub fn from_symbol(symbol: S) -> Self + where + Q: Default, + { Self { state: Default::default(), symbol, @@ -44,10 +50,7 @@ impl Head { } /// Create a new instance from a 2-tuple: ([state](State), symbol) pub fn from_tuple((state, symbol): (State, S)) -> Self { - Self { - state, - symbol, - } + Self { state, symbol } } /// Updates the current [state](State) and returns a new head pub fn with_state(self, State(state): State) -> Self { From 72ff55c51d1733b8674e45110660c9ddce95aea0 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 22:27:15 -0500 Subject: [PATCH 30/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 57 ++++++++++++++++++--------- core/src/actors/exec.rs | 31 +++++++++------ core/src/error.rs | 16 +++++--- core/src/lib.rs | 11 ++++-- core/src/ops/mod.rs | 17 -------- core/src/ops/shift.rs | 13 ------ core/src/tape/tape.rs | 8 ++-- core/src/traits/execute.rs | 10 +++++ core/src/traits/mod.rs | 9 ++++- core/src/traits/symbolic.rs | 2 +- core/src/{ops => traits}/transform.rs | 8 ++++ core/tests/actor.rs | 4 +- rstm/examples/actor.rs | 2 +- rstm/src/turing/state.rs | 2 +- 14 files changed, 108 insertions(+), 82 deletions(-) delete mode 100644 core/src/ops/mod.rs delete mode 100644 core/src/ops/shift.rs create mode 100644 core/src/traits/execute.rs rename core/src/{ops => traits}/transform.rs (70%) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 501b45a..697700e 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -21,32 +21,45 @@ pub struct Actor { } impl Actor { - pub fn new() -> ActorBuilder { - ActorBuilder::new() + pub fn new(State(state): State) -> Self { + Self { + alpha: Vec::new(), + head: Head { + state: State(state), + symbol: 0, + }, + } } - pub fn from_state(State(state): State) -> ActorBuilder { - ActorBuilder::new().state(State(state)) + pub fn with_tape(self, alpha: I) -> Self + where + I: IntoIterator, + { + Self { + alpha: Vec::from_iter(alpha), + ..self + } + } + /// + pub fn builder() -> ActorBuilder { + ActorBuilder::new() } /// Returns an immutable reference to the tape alphabet as a slice pub fn alpha(&self) -> &[S] { &self.alpha } - - pub fn cursor(&self) -> usize { - self.head.symbol - } - /// Returns an immutable reference to the head of the tape - pub const fn head(&self) -> &Head { - &self.head - } - - pub fn head_ref(&self) -> Head<&Q, usize> { + /// Returns an instance of the [Head] with an immutable reference to the state's inner + /// value + pub fn get_head_ref(&self) -> Head<&Q, usize> { Head { state: self.head.state.to_ref(), symbol: self.head.symbol, } } + /// Returns an immutable reference to the head of the tape + pub const fn head(&self) -> &Head { + &self.head + } /// Returns a mutable reference to the head of the tape pub fn head_mut(&mut self) -> &mut Head { &mut self.head @@ -80,6 +93,10 @@ impl Actor { pub fn len(&self) -> usize { self.alpha.len() } + /// Returns the current position of the head on the tape + pub fn position(&self) -> usize { + self.head.symbol + } /// Reads the current symbol at the head of the tape #[cfg_attr( feature = "tracing", @@ -88,7 +105,7 @@ impl Actor { pub fn read(&self) -> Option> { #[cfg(feature = "tracing")] tracing::debug!("Reading the tape..."); - let Head { state, symbol } = self.head_ref(); + let Head { state, symbol } = self.get_head_ref(); self.alpha.get(symbol).map(|value| Head::new(state, value)) } /// Writes the given symbol to the tape @@ -102,7 +119,7 @@ impl Actor { let pos = self.head.symbol; if pos >= self.len() { #[cfg(feature = "tracing")] - tracing::debug!("Appending to the tape..."); + tracing::trace!("Appending to the tape..."); // append to the tape self.alpha.push(value); } else { @@ -124,12 +141,14 @@ impl Actor { S: Clone, { #[cfg(feature = "tracing")] - tracing::debug!("Stepping the tape..."); + tracing::debug!("Transitioning the actor..."); + // write the symbol to the tape self.write(symbol); // set the state of the head self.head.set_state(State(state)); // shift the head in the given direction self.head.shift_inplace(direction); + // read the tape self.read() } } @@ -141,7 +160,7 @@ where { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for (i, c) in self.alpha.iter().enumerate() { - if i == self.cursor() { + if i == self.position() { write!(f, "[{c:?}]")?; } else { write!(f, "{c:?}")?; @@ -158,7 +177,7 @@ where { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for (i, c) in self.alpha.iter().enumerate() { - if i == self.cursor() { + if i == self.position() { write!(f, "[{c}]")?; } else { write!(f, "{c}")?; diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 40d13dd..5bd9318 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ use super::Actor; -use crate::{Error, Head, Program, Symbolic}; +use crate::{Error, Head, Program, Symbolic, Tail}; pub struct Executor { pub(crate) actor: Actor, @@ -14,6 +14,7 @@ impl Executor { pub(crate) fn new(actor: Actor, program: Program) -> Self { Self { actor, program } } + pub fn from_actor(actor: Actor) -> Self where Q: Default, @@ -26,26 +27,31 @@ impl Executor { }, } } - - pub fn with_program(self, program: Program) -> Self { + /// Load a program into the executor + pub fn load(self, program: Program) -> Self { Executor { program, ..self } } + pub fn actor(&self) -> &Actor { + &self.actor + } + #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "run", target = "actor") )] - pub fn run(&mut self) -> Result, Error> + pub fn run(&mut self) -> Result<(), Error> where Q: Clone + PartialEq + core::fmt::Debug + 'static, S: Symbolic, { #[cfg(feature = "tracing")] - tracing::info!("Executing the program using the given actor..."); - while let Some(_) = self.next() { - continue; + tracing::info!("Running the program..."); + for i in self { + #[cfg(feature = "tracing")] + tracing::info!("{head:?}", head = i); } - Ok(self.actor.alpha().to_vec()) + Ok(()) } } @@ -65,17 +71,16 @@ where #[cfg(feature = "tracing")] tracing::info!("Halted"); return None; - } - if let Some(head) = self.actor.read() { + } else if let Some(h) = self.actor().read() { #[cfg(feature = "tracing")] - tracing::info!("{tape:?}", tape = self.actor); - let crate::Tail { + tracing::info!("{tape:?}", tape = self.actor()); + let Tail { direction, state, symbol, } = self .program - .get_head_ref(head) + .get_head_ref(h) .expect("No instruction found for the current head"); return self .actor diff --git a/core/src/error.rs b/core/src/error.rs index 2f1ec4c..5a41b0d 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -18,19 +18,25 @@ pub enum StateError { )] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum Error { - #[error("[IndexError] Out of Bounds: {index} is out of bounds for a length of {len}")] + #[error("[Execution Error] {0}")] + ExecutionError(String), + #[error("[Index Error] Out of Bounds: {index} is out of bounds for a length of {len}")] IndexOutOfBounds { index: usize, len: usize }, - #[error("[Runtime] Runtime Error: {0}")] + #[error("[Runtime Error] {0}")] RuntimeError(String), - #[error("State Error: {0}")] + #[error("[State Error] {0}")] StateError(#[from] StateError), - #[error("Transformation error: {0}")] + #[error("[Transformation Error]: {0}")] TransformationError(String), - #[error("Unknown error: {0}")] + #[error("[Unknown Error] {0}")] Unknown(String), } impl Error { + pub fn execution_error(message: impl ToString) -> Self { + Error::ExecutionError(message.to_string()) + } + pub fn index_out_of_bounds(index: usize, len: usize) -> Self { Error::IndexOutOfBounds { index, len } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 08ad965..eecac6b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -11,8 +11,13 @@ extern crate alloc; #[doc(inline)] pub use self::{ - actors::Actor, error::Error, ops::prelude::*, rules::prelude::*, state::State, tape::Tape, - traits::prelude::*, types::prelude::*, + actors::Actor, + error::Error, + rules::{Program, Rule}, + state::State, + tape::Tape, + traits::prelude::*, + types::prelude::*, }; #[allow(unused_macros)] @@ -31,7 +36,6 @@ pub(crate) mod seal; #[doc(hidden)] pub mod actors; pub mod error; -pub mod ops; pub mod rules; pub mod state; pub mod tape; @@ -41,7 +45,6 @@ pub mod types; pub mod prelude { pub use crate::actors::prelude::*; pub use crate::error::Error; - pub use crate::ops::prelude::*; pub use crate::rules::prelude::*; pub use crate::state::prelude::*; pub use crate::tape::prelude::*; diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs deleted file mode 100644 index d52e805..0000000 --- a/core/src/ops/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - Appellation: ops - Contrib: FL03 -*/ -//! # Operations -//! -//! Overloadable operations used throughout the `rstm` crate. -#[doc(inline)] -pub use self::transform::*; - -#[doc(hidden)] -pub mod shift; -pub mod transform; - -pub(crate) mod prelude { - pub use super::transform::*; -} diff --git a/core/src/ops/shift.rs b/core/src/ops/shift.rs deleted file mode 100644 index ed14e56..0000000 --- a/core/src/ops/shift.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* - Appellation: shift - Contrib: FL03 -*/ - -/// [`Shift`] describes a generalized shift operation; -/// w.r.t. Turing machines, Moore (1990) describes a shift operation as a _movement_ of the -/// tape head -pub trait Shift { - type Output; - - fn shift(&self, tape: &T) -> Self::Output; -} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 89c439f..2a7da66 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -8,12 +8,12 @@ use core::cell::Cell; #[cfg(feature = "alloc")] use alloc::vec::Vec; -/// The [`Tape`] is defined to be a one-dimensional surface evenly divided into cells capable -/// of storing symbols. The tape is infinite in both directions allowing the head, or actor, to -/// move without bounds, extending the tape as needed. +/// In-line with the Turing machine model, the [`Tape`] is a one-dimensional surface evenly +/// divided into cells capable of storing symbols. The tape is infinite in both directions +/// allowing the head, or actor, to move without bounds, extending the tape as needed. /// /// -/// Here, the [Tape] employs the use of a [Vec] to store symbols while leveraging a +/// Here, the tape employs the use of a [Vec] to store symbols while leveraging a /// [usize] to keep track of the current position of the tape head. Moreover, the tape /// stores the number of steps or operations taken by the tape head in a [Cell]. /// This is done to quantify the impact of operations whose directions are defined to diff --git a/core/src/traits/execute.rs b/core/src/traits/execute.rs new file mode 100644 index 0000000..7a9e427 --- /dev/null +++ b/core/src/traits/execute.rs @@ -0,0 +1,10 @@ +/* + Appellation: execute + Contrib: FL03 +*/ + +pub trait Execute { + type Output; + + fn execute(&self) -> Result; +} diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index e1caf7c..2dbf4d9 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,14 +3,19 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::symbolic::*; +pub use self::{execute::*, symbolic::*, transform::*}; + +pub mod execute; +pub mod symbolic; +pub mod transform; #[doc(hidden)] pub mod cspace; #[doc(hidden)] pub mod io; -pub mod symbolic; pub(crate) mod prelude { + pub use super::execute::*; pub use super::symbolic::*; + pub use super::transform::*; } diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index 9b468c9..be09d20 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -18,7 +18,7 @@ pub trait Alphabet { fn as_mut_slice(&mut self) -> &mut [Self::Elem]; fn is_empty(&self) -> bool { - self.as_slice().is_empty() + self.len() == 0 } fn len(&self) -> usize { diff --git a/core/src/ops/transform.rs b/core/src/traits/transform.rs similarity index 70% rename from core/src/ops/transform.rs rename to core/src/traits/transform.rs index 2dea121..faabec5 100644 --- a/core/src/ops/transform.rs +++ b/core/src/traits/transform.rs @@ -3,6 +3,14 @@ Contrib: FL03 */ +/// [`Shift`] describes a generalized shift operation; +/// w.r.t. Turing machines, Moore (1990) describes a shift operation as a _movement_ of the +/// tape head +pub trait Shift { + type Output; + + fn shift(&self, tape: &T) -> Self::Output; +} /// [`Transform`] is describes a binary operation capable of applying some transformation. /// More commonly, the typical "rustic" manner of which an object is transformed is through /// the [`map`] method, which applies a function to a value and returns a new value. diff --git a/core/tests/actor.rs b/core/tests/actor.rs index 192aed6..d40e5f6 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -24,7 +24,7 @@ lazy_static::lazy_static! { } #[test] -fn test_actor() { +fn busy_beaver() { let input = [0_usize; 10]; let program = Program::new() @@ -32,6 +32,6 @@ fn test_actor() { .initial_state(INITIAL_STATE) .build(); - let actor = Actor::new().alpha(input).state(State(0)).build(); + let actor = Actor::new(State(0)).with_tape(input); assert!(actor.execute(program).run().is_ok()); } diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 7254709..4ee2e05 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -28,7 +28,7 @@ fn main() -> Result<(), Box> { .build(); // create a new instance of the machine - let tm = dbg!(Actor::new().alpha(alpha).state(initial_state).build()); + let tm = dbg!(Actor::new(initial_state).with_tape(alpha)); let out = tm.execute(program).run()?; println!("Output: {out:?}"); Ok(()) diff --git a/rstm/src/turing/state.rs b/rstm/src/turing/state.rs index c1b9651..0cc7932 100644 --- a/rstm/src/turing/state.rs +++ b/rstm/src/turing/state.rs @@ -35,7 +35,7 @@ impl TMS { pub fn into_halt(self) -> State> { match self { TMS::Halt(state) => state, - TMS::State(state) => State(Halt(state.into_inner())), + TMS::State(state) => state.halt(), } } From a32fe07b83f8b94af984c3f6fd8813b2e05a4777 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Wed, 21 Aug 2024 23:53:36 -0500 Subject: [PATCH 31/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 61 ++++++++++++++++++++++++------ core/src/actors/exec.rs | 6 +-- core/src/rules/builders/program.rs | 2 + core/src/tape/tape.rs | 22 ++++------- core/src/types/head.rs | 36 ++++-------------- rstm/examples/actor.rs | 10 ++++- rstm/examples/basic.rs | 19 +++++++++- rstm/src/turing.rs | 18 ++++----- 8 files changed, 102 insertions(+), 72 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 697700e..cd65ffe 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -98,16 +98,34 @@ impl Actor { self.head.symbol } /// Reads the current symbol at the head of the tape + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "get", target = "actor") + )] + pub fn get(&self) -> Option<&S> { + self.alpha().get(self.position()) + } + + pub fn get_head(&self) -> Option> { + self.get().map(|symbol| Head { + state: self.head.state(), + symbol, + }) + } + /// Reads the current symbol at the head of the tape #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "read", target = "actor") )] pub fn read(&self) -> Option> { #[cfg(feature = "tracing")] - tracing::debug!("Reading the tape..."); - let Head { state, symbol } = self.get_head_ref(); - self.alpha.get(symbol).map(|value| Head::new(state, value)) + tracing::trace!("Reading the tape..."); + self.alpha.get(self.position()).map(|symbol| Head { + state: self.head.state(), + symbol, + }) } + /// Writes the given symbol to the tape #[cfg_attr( feature = "tracing", @@ -115,7 +133,7 @@ impl Actor { )] pub fn write(&mut self, value: S) { #[cfg(feature = "tracing")] - tracing::debug!("Writing to the tape..."); + tracing::trace!("Writing to the tape..."); let pos = self.head.symbol; if pos >= self.len() { #[cfg(feature = "tracing")] @@ -127,6 +145,27 @@ impl Actor { } } /// Performs a single step of the Turing machine + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "handle", target = "actor") + )] + pub(crate) fn handle( + &mut self, + direction: Direction, + State(next_state): State, + symbol: S, + ) { + #[cfg(feature = "tracing")] + tracing::trace!("Transitioning the actor..."); + // write the symbol to the tape + self.write(symbol); + // update the head of the actor + self.head = Head { + state: State(next_state), + symbol: direction.apply(self.head.symbol), + }; + } + /// Performs a single step of the Turing machine #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "step", target = "actor") @@ -141,13 +180,15 @@ impl Actor { S: Clone, { #[cfg(feature = "tracing")] - tracing::debug!("Transitioning the actor..."); + tracing::trace!("Transitioning the actor..."); + // write the symbol to the tape self.write(symbol); - // set the state of the head - self.head.set_state(State(state)); - // shift the head in the given direction - self.head.shift_inplace(direction); + // update the head of the actor + self.head = Head { + state: State(state), + symbol: direction.apply(self.head.symbol), + }; // read the tape self.read() } @@ -155,7 +196,6 @@ impl Actor { impl core::fmt::Debug for Actor where - Q: core::fmt::Debug, S: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -172,7 +212,6 @@ where impl core::fmt::Display for Actor where - Q: core::fmt::Display, S: core::fmt::Display, { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 5bd9318..ec5e981 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -82,10 +82,8 @@ where .program .get_head_ref(h) .expect("No instruction found for the current head"); - return self - .actor - .step(direction, state.cloned(), *symbol) - .map(|h| h.cloned()); + self.actor.handle(direction, state.cloned(), *symbol); + return self.actor.read().map(|h| h.cloned()); } else { #[cfg(feature = "tracing")] tracing::error!("No instruction found for the current head"); diff --git a/core/src/rules/builders/program.rs b/core/src/rules/builders/program.rs index 698549a..ecbfc07 100644 --- a/core/src/rules/builders/program.rs +++ b/core/src/rules/builders/program.rs @@ -4,6 +4,8 @@ */ use crate::rules::{Program, Rule}; use crate::State; + +#[derive(Default)] pub struct ProgramBuilder { initial_state: Option>, rules: Vec>, diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 2a7da66..4fc3262 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -115,14 +115,7 @@ impl Tape { .ok_or(Error::index_out_of_bounds(self.cursor, self.len())) } /// - pub fn write(&mut self, direction: Direction, symbol: S) { - self.write_symbol(symbol); - self.shift(direction); - self.on_update(); - } - - /// - fn write_symbol(&mut self, symbol: S) { + pub fn write(&mut self, symbol: S) { if self.cursor < self.store.len() { self.store[self.cursor] = symbol; } else { @@ -142,20 +135,18 @@ impl Tape { { let head = Head::new(state, symbol.clone()); let mut tape = self; - tape.write(direction, symbol); + tape.write(symbol); tape.shift(direction); (tape, head) } - pub fn update_inplace( + pub fn update_inplace( &mut self, direction: Direction, - state: State, symbol: S, - ) -> State { - self.write(direction, symbol); + ) { + self.write(symbol); self.shift(direction); - state } pub fn apply_inplace(&mut self, tail: Tail) -> State { @@ -164,7 +155,8 @@ impl Tape { state, symbol, } = tail; - self.update_inplace(direction, state, symbol) + self.update_inplace(direction, symbol); + state } fn on_update(&self) { diff --git a/core/src/types/head.rs b/core/src/types/head.rs index a820512..c2324c1 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -130,12 +130,14 @@ impl Head { symbol: &mut self.symbol, } } -} -impl Head { - pub fn read_tape<'a, S>(&self, tape: &'a [S]) -> Option<&'a S> { + pub fn read<'a, T>(self, tape: &'a [T]) -> Option<&'a ::Output> where S: core::slice::SliceIndex<[T]> { tape.get(self.symbol) } +} + +impl Head { + pub fn shift(self, direction: crate::Direction) -> Self { Self { @@ -143,7 +145,7 @@ impl Head { ..self } } - + pub fn shift_inplace(&mut self, direction: crate::Direction) { self.symbol = direction.apply(self.symbol); } @@ -168,7 +170,7 @@ impl<'a, Q, S> Head<&'a Q, &'a S> { { Head { state: self.state.copied(), - symbol: self.symbol.clone(), + symbol: *self.symbol, } } } @@ -197,30 +199,6 @@ impl<'a, Q, S> Head<&'a mut Q, &'a mut S> { } } -impl<'a, Q, S> Head<*const Q, *const S> { - pub fn cloned(&self) -> Head<*const Q, *const S> - where - Q: Clone, - S: Clone, - { - Head { - state: self.state.clone(), - symbol: self.symbol.clone(), - } - } - - pub unsafe fn copied(&self) -> Head - where - Q: Copy, - S: Copy, - { - Head { - state: State(*self.state.0), - symbol: *self.symbol, - } - } -} - impl From<(Q, S)> for Head { fn from((state, symbol): (Q, S)) -> Self { Self::new(State(state), symbol) diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 4ee2e05..31fd14e 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -9,7 +9,7 @@ use rstm::{ruleset, Actor, Program, State}; fn main() -> Result<(), Box> { _tracing(); // initialize the tape data - let alpha: Vec = vec![0, 1, 1, 0, 1, 0, 1, 0]; + let alpha = vec![0_i8; 10]; // initialize the state of the machine let initial_state = State(0); // define the ruleset for the machine @@ -37,9 +37,15 @@ fn main() -> Result<(), Box> { fn _tracing() { let timer = tracing_subscriber::fmt::time::uptime(); tracing_subscriber::fmt() - .with_max_level(tracing::Level::TRACE) + .with_max_level(tracing::Level::INFO) .with_target(false) .with_timer(timer) .init(); tracing::info!("Welcome to rstm!"); } + +pub enum S3 { + A, + B, + C, +} \ No newline at end of file diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 31bb439..6b0ab15 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -7,7 +7,7 @@ extern crate rstm; use rstm::{ruleset, Program, State, Tape, TM}; fn main() -> Result<(), Box> { - tracing_subscriber::fmt().with_target(false).init(); + _tracing("debug"); // initialize the tape data let alpha = [0_usize; 10]; @@ -29,3 +29,20 @@ fn main() -> Result<(), Box> { tm.execute()?; Ok(()) } + +fn _tracing(level: &str) { + let level = match level { + "debug" => tracing::Level::DEBUG, + "error" => tracing::Level::ERROR, + "trace" => tracing::Level::TRACE, + "warn" => tracing::Level::WARN, + _ => tracing::Level::INFO, + }; + let timer = tracing_subscriber::fmt::time::uptime(); + tracing_subscriber::fmt() + .with_max_level(level) + .with_target(false) + .with_timer(timer) + .init(); + tracing::info!("Welcome to rstm!"); +} \ No newline at end of file diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 2905fa4..24f3a3d 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -79,10 +79,10 @@ impl TM { S: Symbolic, { #[cfg(feature = "tracing")] - tracing::info!("Running the program..."); + tracing::trace!("Executing the program..."); loop { #[cfg(feature = "tracing")] - tracing::info!("{}", &self.tape); + tracing::info!("{tape}", tape = self.tape()); match self.process() { Some(_) => { if self.state.is_halt() { @@ -104,14 +104,11 @@ impl TM { )] fn process(&mut self) -> Option> where - Q: Clone + PartialEq + 'static, + Q: Clone + PartialEq, S: Clone + PartialEq, { #[cfg(feature = "tracing")] - tracing::info!("Stepping..."); - if self.state.is_halt() { - return None; - } + tracing::trace!("Processing the current instruction..."); // Get the first instruction for the current head if let Some(Tail { direction, @@ -120,10 +117,11 @@ impl TM { }) = self .program .get_head_ref(self.read()?) - .map(|tail| tail.cloned()) { - self.state = self.tape.update_inplace(direction, state, symbol); - return self.read(); + // + self.tape.update_inplace(direction, symbol.clone()); + self.state = state.cloned(); + return Some(Head::new(state, symbol)); } unreachable!("No instruction found for the current head") } From 1a763a07dc9ab109005c7cd1e3ab2082d0bd8798 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 22 Aug 2024 06:50:45 -0500 Subject: [PATCH 32/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 55 +++++++++---------- core/src/actors/exec.rs | 10 ++-- core/src/actors/mod.rs | 11 ++++ core/src/tape/mod.rs | 30 ++++++++--- core/src/tape/tape.rs | 112 ++++++++++++++++----------------------- core/src/types/head.rs | 35 +++++------- core/tests/actor.rs | 2 +- rstm/examples/actor.rs | 4 +- rstm/examples/basic.rs | 2 +- rstm/src/turing.rs | 6 +-- 10 files changed, 134 insertions(+), 133 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index cd65ffe..480fc87 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -7,7 +7,7 @@ pub use self::builder::ActorBuilder; use super::Executor; use crate::rules::Program; -use crate::{Direction, Head, State}; +use crate::{Direction, Error, Head, State}; /// An [Actor] describes a Turing machine with a moving head (TMH). /// @@ -18,16 +18,25 @@ pub struct Actor { pub(crate) alpha: Vec, /// the head of the tape pub(crate) head: Head, + /// the number of steps taken by the actor + pub(crate) steps: usize, } impl Actor { - pub fn new(State(state): State) -> Self { + /// + pub fn new() -> ActorBuilder { + ActorBuilder::new() + } + /// Constructs a new [Actor] with the given state; assumes the tape is empty and the head + /// is located at `0`. + pub fn from_state(State(state): State) -> Self { Self { alpha: Vec::new(), head: Head { state: State(state), symbol: 0, }, + steps: 0, } } @@ -40,10 +49,7 @@ impl Actor { ..self } } - /// - pub fn builder() -> ActorBuilder { - ActorBuilder::new() - } + /// Returns an immutable reference to the tape alphabet as a slice pub fn alpha(&self) -> &[S] { &self.alpha @@ -117,13 +123,16 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "read", target = "actor") )] - pub fn read(&self) -> Option> { + pub fn read(&self) -> Result, Error> { #[cfg(feature = "tracing")] tracing::trace!("Reading the tape..."); - self.alpha.get(self.position()).map(|symbol| Head { - state: self.head.state(), - symbol, - }) + self.alpha + .get(self.position()) + .map(|symbol| Head { + state: self.head.state(), + symbol, + }) + .ok_or(Error::index_out_of_bounds(self.position(), self.len())) } /// Writes the given symbol to the tape @@ -149,12 +158,7 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "handle", target = "actor") )] - pub(crate) fn handle( - &mut self, - direction: Direction, - State(next_state): State, - symbol: S, - ) { + pub(crate) fn handle(&mut self, direction: Direction, State(next_state): State, symbol: S) { #[cfg(feature = "tracing")] tracing::trace!("Transitioning the actor..."); // write the symbol to the tape @@ -175,7 +179,7 @@ impl Actor { direction: Direction, State(state): State, symbol: S, - ) -> Option> + ) -> Result, Error> where S: Clone, { @@ -192,6 +196,10 @@ impl Actor { // read the tape self.read() } + + fn on_update(&mut self) { + self.steps += 1; + } } impl core::fmt::Debug for Actor @@ -238,7 +246,7 @@ mod builder { } impl ActorBuilder { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { alpha: Vec::new(), state: None, @@ -246,14 +254,6 @@ mod builder { } } - pub fn from_state(State(state): State) -> Self { - Self { - alpha: Vec::new(), - state: Some(State(state)), - symbol: 0, - } - } - pub fn alpha(self, alpha: I) -> Self where I: IntoIterator, @@ -298,6 +298,7 @@ mod builder { state: state.unwrap_or_default(), symbol, }, + steps: 0, } } } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index ec5e981..e9cb3f1 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -57,7 +57,7 @@ impl Executor { impl Iterator for Executor where - Q: Clone + PartialEq + core::fmt::Debug + 'static, + Q: Clone + PartialEq + 'static, S: Symbolic, { type Item = Head; @@ -71,7 +71,7 @@ where #[cfg(feature = "tracing")] tracing::info!("Halted"); return None; - } else if let Some(h) = self.actor().read() { + } else if let Ok(h) = self.actor().read() { #[cfg(feature = "tracing")] tracing::info!("{tape:?}", tape = self.actor()); let Tail { @@ -83,11 +83,11 @@ where .get_head_ref(h) .expect("No instruction found for the current head"); self.actor.handle(direction, state.cloned(), *symbol); - return self.actor.read().map(|h| h.cloned()); + return self.actor.read().map(|h| h.cloned()).ok(); } else { #[cfg(feature = "tracing")] - tracing::error!("No instruction found for the current head"); - panic!("No head found at the current position"); + tracing::error!("No symbol found at {}", self.actor.position()); + panic!("No symbol found at {}", self.actor.position()); } } } diff --git a/core/src/actors/mod.rs b/core/src/actors/mod.rs index 0a0ed04..b8cff85 100644 --- a/core/src/actors/mod.rs +++ b/core/src/actors/mod.rs @@ -12,3 +12,14 @@ pub(crate) mod prelude { pub use super::actor::Actor; pub use super::exec::Executor; } + +use crate::{rules::Program, Alphabet}; + +pub trait Model { + type Alpha: Alphabet; +} +pub trait Runtime { + fn load(&mut self, program: Program); + + fn run(&mut self); +} diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index ab569a4..04452ad 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -15,21 +15,21 @@ pub(crate) mod prelude { pub use super::tape::Tape; } -/// A trait for tape-like structures. -#[doc(hidden)] +/// [RawTape] is a trait that provides a common interface for tape-like structures. pub trait RawTape { type Elem; private!(); fn as_slice(&self) -> &[Self::Elem]; -} -#[doc(hidden)] -pub trait Reader { - type Output; + fn is_empty(&self) -> bool { + self.len() == 0 + } - fn read(&self) -> Self::Output; + fn len(&self) -> usize { + self.as_slice().len() + } } /* @@ -43,6 +43,14 @@ impl RawTape for [T] { fn as_slice(&self) -> &[Self::Elem] { &self } + + fn is_empty(&self) -> bool { + <[T]>::is_empty(self) + } + + fn len(&self) -> usize { + <[T]>::len(self) + } } impl RawTape for Vec { @@ -53,4 +61,12 @@ impl RawTape for Vec { fn as_slice(&self) -> &[Self::Elem] { Vec::as_slice(self) } + + fn is_empty(&self) -> bool { + Vec::is_empty(self) + } + + fn len(&self) -> usize { + Vec::len(self) + } } diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 4fc3262..84b7c37 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -2,7 +2,7 @@ Appellation: tape Contrib: FL03 */ -use crate::{Direction, Error, Head, State, Tail}; +use crate::{Direction, Error}; use core::cell::Cell; #[cfg(feature = "alloc")] @@ -21,7 +21,7 @@ use alloc::vec::Vec; /// to a translation or shift in space, however, staying in place does not result in /// any movement, shift, or translation within space. That being said, staying still /// is an operation that does result in some change in-time. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Tape { cursor: usize, @@ -73,9 +73,13 @@ impl Tape { pub fn clear(&mut self) { self.store.clear(); } - /// 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> + where + I: core::slice::SliceIndex<[S]>, + { + self.store.get(idx) } /// Checks if the tape is empty; returns `true` if the tape is empty, /// `false` otherwise. @@ -90,94 +94,57 @@ impl Tape { pub fn iter_mut(&mut self) -> core::slice::IterMut { self.store.iter_mut() } + /// Returns the number of elements in the tape. + pub fn len(&self) -> usize { + self.store.len() + } + /// Removes and returns the last element of the tape, or `None` if it is empty. + pub fn pop(&mut self) -> Option { + self.store.pop() + } + /// Appends the given element to the back of the collection. + pub fn push(&mut self, symbol: S) { + self.store.push(symbol); + } /// Returns the number of steps or operations taken by the tape head; /// this provides a measure of the impact of operations whose directions are defined to be /// [Stay](Direction::Stay). pub fn ticks(&self) -> usize { self.ticks.get() } - - pub fn to_string(&self) -> String - where - S: core::fmt::Display, - { - format!("step ({}): {}", self.ticks(), self) - } - /// Returns the current position of the tape head; pub fn position(&self) -> usize { self.cursor } - - /// Returns an owned reference to the current symbol on the tape + /// Attempts to read the symbol at the current position of the tape head. pub fn read(&self) -> Result<&S, Error> { self.get(self.cursor) .ok_or(Error::index_out_of_bounds(self.cursor, self.len())) } - /// + /// Writes the given symbol to the tape at the current position of the tape head. pub fn write(&mut self, symbol: S) { - if self.cursor < self.store.len() { - self.store[self.cursor] = symbol; - } else { + if self.cursor == usize::MAX { + self.store.insert(0, symbol); + } else if self.cursor == self.store.len() { self.store.push(symbol); + } else { + self.store[self.cursor] = symbol; } } - fn shift(&mut self, direction: Direction) -> usize { + pub fn update(&mut self, direction: Direction, symbol: S) { self.on_update(); - self.cursor = direction.apply(self.cursor) % self.store.len(); - self.position() - } - - pub fn update(self, direction: Direction, state: State, symbol: S) -> (Self, Head) - where - S: Clone, - { - let head = Head::new(state, symbol.clone()); - let mut tape = self; - tape.write(symbol); - tape.shift(direction); - (tape, head) - } - - pub fn update_inplace( - &mut self, - direction: Direction, - symbol: S, - ) { self.write(symbol); self.shift(direction); } - pub fn apply_inplace(&mut self, tail: Tail) -> State { - let Tail { - direction, - state, - symbol, - } = tail; - self.update_inplace(direction, symbol); - state - } - fn on_update(&self) { self.ticks.set(self.ticks.get() + 1); } - /// 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> - where - I: core::slice::SliceIndex<[S]>, - { - self.store.get(idx) - } - /// Removes and returns the last element of the tape, or `None` if it is empty. - pub fn pop(&mut self) -> Option { - self.store.pop() - } - /// Appends the given element to the back of the collection. - pub fn push(&mut self, symbol: S) { - self.store.push(symbol); + fn shift(&mut self, direction: Direction) -> usize { + self.cursor = direction.apply(self.cursor) % self.store.len(); + self.position() } } @@ -229,6 +196,21 @@ impl core::ops::DerefMut for Tape { } } +impl core::fmt::Debug for Tape +where + S: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + for (i, c) in self.store.iter().enumerate() { + match c { + s if i == self.cursor => write!(f, "[{s:?}]")?, + _ => write!(f, "{c:?}")?, + } + } + Ok(()) + } +} + impl core::fmt::Display for Tape where S: core::fmt::Display, diff --git a/core/src/types/head.rs b/core/src/types/head.rs index c2324c1..57c1a44 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -63,19 +63,19 @@ impl Head { pub fn with_symbol(self, symbol: S) -> Self { Self { symbol, ..self } } - /// Returns a reference to the current [state](State) and symbol returing a 2-tuple + /// Returns a reference to the current 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 + /// Consumes the head and returns the current 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 + /// Returns a mutable reference to the current 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) + /// Updates the current state pub fn set_state(&mut self, state: State) { self.state = state; } @@ -83,11 +83,11 @@ impl Head { pub fn set_symbol(&mut self, symbol: S) { self.symbol = symbol; } - /// Returns a reference to the current [state](State) + /// Returns a reference to the current state pub fn state(&self) -> State<&Q> { self.state.to_ref() } - /// Returns a mutable reference to the current [state](State) + /// Returns a mutable reference to the current [State] pub fn state_mut(&mut self) -> State<&mut Q> { self.state.to_mut() } @@ -99,7 +99,7 @@ impl Head { pub fn symbol_mut(&mut self) -> &mut S { &mut self.symbol } - /// Updates the current [state](State) and symbol + /// Updates the current [State] and symbol pub fn update(&mut self, state: Option>, symbol: Option) { if let Some(state) = state { self.state = state; @@ -109,43 +109,36 @@ impl Head { } } /// Converts the current head into a new head with immutable references to the current state and symbol - pub fn to_ref<'a>(&'a self) -> Head<&Q, &S> - where - Q: 'a, - S: 'a, - { + pub fn to_ref(&self) -> Head<&Q, &S> { Head { state: self.state.to_ref(), symbol: &self.symbol, } } /// Converts the current head into a new head with mutable references to the current state and symbol - pub fn to_mut<'a>(&'a mut self) -> Head<&mut Q, &mut S> - where - Q: 'a, - S: 'a, - { + pub fn to_mut(&mut self) -> Head<&mut Q, &mut S> { Head { state: self.state.to_mut(), symbol: &mut self.symbol, } } - pub fn read<'a, T>(self, tape: &'a [T]) -> Option<&'a ::Output> where S: core::slice::SliceIndex<[T]> { + pub fn read(self, tape: &'_ [T]) -> Option<&::Output> + where + S: core::slice::SliceIndex<[T]>, + { tape.get(self.symbol) } } impl Head { - - pub fn shift(self, direction: crate::Direction) -> Self { Self { symbol: direction.apply(self.symbol), ..self } } - + pub fn shift_inplace(&mut self, direction: crate::Direction) { self.symbol = direction.apply(self.symbol); } diff --git a/core/tests/actor.rs b/core/tests/actor.rs index d40e5f6..a5e44c6 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -32,6 +32,6 @@ fn busy_beaver() { .initial_state(INITIAL_STATE) .build(); - let actor = Actor::new(State(0)).with_tape(input); + let actor = Actor::from_state(State(0)).with_tape(input); assert!(actor.execute(program).run().is_ok()); } diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 31fd14e..3507cba 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -28,7 +28,7 @@ fn main() -> Result<(), Box> { .build(); // create a new instance of the machine - let tm = dbg!(Actor::new(initial_state).with_tape(alpha)); + let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); let out = tm.execute(program).run()?; println!("Output: {out:?}"); Ok(()) @@ -48,4 +48,4 @@ pub enum S3 { A, B, C, -} \ No newline at end of file +} diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 6b0ab15..568b97f 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -45,4 +45,4 @@ fn _tracing(level: &str) { .with_timer(timer) .init(); tracing::info!("Welcome to rstm!"); -} \ No newline at end of file +} diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 24f3a3d..8a4800b 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -114,12 +114,10 @@ impl TM { direction, state, symbol, - }) = self - .program - .get_head_ref(self.read()?) + }) = self.program.get_head_ref(self.read()?) { // - self.tape.update_inplace(direction, symbol.clone()); + self.tape.update(direction, symbol.clone()); self.state = state.cloned(); return Some(Head::new(state, symbol)); } From 0f74f56f75bafbef1b26b370430ee06a5c4f7617 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 22 Aug 2024 07:15:24 -0500 Subject: [PATCH 33/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 58 ++++++++++++++++++------------------- core/src/actors/exec.rs | 46 +++++++++++++++++------------ core/src/rules/mod.rs | 6 ++-- core/src/rules/rule.rs | 4 +-- core/src/traits/symbolic.rs | 2 ++ core/src/types/tail.rs | 10 +++++-- 6 files changed, 70 insertions(+), 56 deletions(-) diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 480fc87..baf8042 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -23,7 +23,6 @@ pub struct Actor { } impl Actor { - /// pub fn new() -> ActorBuilder { ActorBuilder::new() } @@ -49,19 +48,10 @@ impl Actor { ..self } } - /// Returns an immutable reference to the tape alphabet as a slice pub fn alpha(&self) -> &[S] { &self.alpha } - /// Returns an instance of the [Head] with an immutable reference to the state's inner - /// value - pub fn get_head_ref(&self) -> Head<&Q, usize> { - Head { - state: self.head.state.to_ref(), - symbol: self.head.symbol, - } - } /// Returns an immutable reference to the head of the tape pub const fn head(&self) -> &Head { &self.head @@ -70,6 +60,14 @@ impl Actor { pub fn head_mut(&mut self) -> &mut Head { &mut self.head } + /// Returns an instance of the [Head] with an immutable reference to the state's inner + /// value + pub fn head_ref(&self) -> Head<&Q, usize> { + Head { + state: self.head.state.to_ref(), + symbol: self.head.symbol, + } + } /// Returns an instance of the state with an immutable reference to the inner value pub fn state(&self) -> State<&Q> { self.head.state() @@ -78,11 +76,23 @@ impl Actor { pub fn state_mut(&mut self) -> State<&mut Q> { self.head.state_mut() } + /// Returns the number of steps taken by the actor + pub fn steps(&self) -> usize { + self.steps + } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. pub fn execute(self, program: Program) -> Executor { Executor::new(self, program) } + /// Reads the current symbol at the head of the tape + #[cfg_attr( + feature = "tracing", + tracing::instrument(skip_all, name = "get", target = "actor") + )] + pub fn get(&self) -> Option<&S> { + self.alpha().get(self.position()) + } /// Checks if the tape is empty pub fn is_empty(&self) -> bool { self.alpha.is_empty() @@ -104,21 +114,6 @@ impl Actor { self.head.symbol } /// Reads the current symbol at the head of the tape - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "get", target = "actor") - )] - pub fn get(&self) -> Option<&S> { - self.alpha().get(self.position()) - } - - pub fn get_head(&self) -> Option> { - self.get().map(|symbol| Head { - state: self.head.state(), - symbol, - }) - } - /// Reads the current symbol at the head of the tape #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, name = "read", target = "actor") @@ -143,8 +138,13 @@ impl Actor { pub fn write(&mut self, value: S) { #[cfg(feature = "tracing")] tracing::trace!("Writing to the tape..."); - let pos = self.head.symbol; - if pos >= self.len() { + let pos = self.position(); + + if pos == usize::MAX { + #[cfg(feature = "tracing")] + tracing::trace!("Prepending to the tape..."); + + } else if pos >= self.len() { #[cfg(feature = "tracing")] tracing::trace!("Appending to the tape..."); // append to the tape @@ -158,14 +158,14 @@ impl Actor { feature = "tracing", tracing::instrument(skip_all, name = "handle", target = "actor") )] - pub(crate) fn handle(&mut self, direction: Direction, State(next_state): State, symbol: S) { + pub(crate) fn handle(&mut self, direction: Direction, State(state): State, symbol: S) { #[cfg(feature = "tracing")] tracing::trace!("Transitioning the actor..."); // write the symbol to the tape self.write(symbol); // update the head of the actor self.head = Head { - state: State(next_state), + state: State(state), symbol: direction.apply(self.head.symbol), }; } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index e9cb3f1..5cd336c 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -3,16 +3,18 @@ Contrib: FL03 */ use super::Actor; -use crate::{Error, Head, Program, Symbolic, Tail}; +use crate::{Error, Head, Program, Symbolic}; pub struct Executor { pub(crate) actor: Actor, pub(crate) program: Program, + /// the number of steps taken by the actor + pub(crate) steps: usize, } impl Executor { pub(crate) fn new(actor: Actor, program: Program) -> Self { - Self { actor, program } + Self { actor, program, steps: 0 } } pub fn from_actor(actor: Actor) -> Self @@ -25,6 +27,7 @@ impl Executor { initial_state: Default::default(), rules: Vec::new(), }, + steps: 0, } } /// Load a program into the executor @@ -42,14 +45,13 @@ impl Executor { )] pub fn run(&mut self) -> Result<(), Error> where - Q: Clone + PartialEq + core::fmt::Debug + 'static, + Q: Clone + PartialEq + 'static, S: Symbolic, { #[cfg(feature = "tracing")] tracing::info!("Running the program..."); - for i in self { - #[cfg(feature = "tracing")] - tracing::info!("{head:?}", head = i); + for _h in self { + continue; } Ok(()) } @@ -67,23 +69,29 @@ where tracing::instrument(skip_all, name = "next", target = "actor") )] fn next(&mut self) -> Option { + // increment the number of steps taken + self.steps += 1; + #[cfg(feature = "tracing")] + tracing::info!("{tape:?}", tape = self.actor()); + // check if the actor is halted if self.actor.is_halted() { #[cfg(feature = "tracing")] - tracing::info!("Halted"); + tracing::warn!("Detected a halted state; terminating the program..."); return None; - } else if let Ok(h) = self.actor().read() { - #[cfg(feature = "tracing")] - tracing::info!("{tape:?}", tape = self.actor()); - let Tail { - direction, - state, - symbol, - } = self + } + // read the tape + let head = Head { state: self.actor.state().cloned(), symbol: self.actor.get().copied().unwrap_or_default() }; + // execute the program + if let Some(tail) = self .program - .get_head_ref(h) - .expect("No instruction found for the current head"); - self.actor.handle(direction, state.cloned(), *symbol); - return self.actor.read().map(|h| h.cloned()).ok(); + .get_head_ref(head.to_ref()) { + // get the next head + let next = tail.cloned().into_head(); + // process the instruction + self.actor + .handle(tail.direction(), tail.state.cloned(), *tail.symbol); + // return the head + return Some(next); } else { #[cfg(feature = "tracing")] tracing::error!("No symbol found at {}", self.actor.position()); diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index d92edd1..5c2e822 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -106,7 +106,7 @@ impl Directive for Rule { } fn next_state(&self) -> State<&'_ Q> { - self.tail().next_state() + self.tail().state() } fn value(&self) -> &S { @@ -130,11 +130,11 @@ impl Directive for crate::Tail { } fn next_state(&self) -> State<&'_ Q> { - self.next_state() + self.state() } fn value(&self) -> &S { - &self.write_symbol() + &self.symbol() } } diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index d1a3e20..32cf33b 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -58,10 +58,10 @@ impl Rule { } /// Returns the next [State] of the system pub fn next_state(&self) -> State<&'_ Q> { - self.tail().next_state() + self.tail().state() } /// Returns the value which for which the current object will be replaced with pub const fn write_symbol(&self) -> &S { - self.tail().write_symbol() + self.tail().symbol() } } diff --git a/core/src/traits/symbolic.rs b/core/src/traits/symbolic.rs index be09d20..57766d2 100644 --- a/core/src/traits/symbolic.rs +++ b/core/src/traits/symbolic.rs @@ -35,6 +35,7 @@ pub trait Symbolic where Self: Clone + Copy + + Default + Eq + Ord + PartialEq @@ -104,6 +105,7 @@ impl Alphabet for Vec { impl Symbolic for S where S: Copy + + Default + Eq + Ord + core::fmt::Debug diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 1c89fc9..5dd860a 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -46,12 +46,16 @@ impl Tail { pub fn direction(&self) -> Direction { self.direction } - /// Returns the next [state](State) the agent is instructed to move to - pub fn next_state(&self) -> State<&'_ Q> { + /// Returns the next state with an immutable reference to the inner value + pub fn state(&self) -> State<&'_ Q> { self.state.to_ref() } + /// Returns the next state with a mutable reference to the inner value + pub fn state_mut(&mut self) -> State<&'_ mut Q> { + self.state.to_mut() + } /// Returns the symbol the [head](Head) is instructed to write - pub const fn write_symbol(&self) -> &S { + pub const fn symbol(&self) -> &S { &self.symbol } /// Consumes the tail and returns a new instance of the [Head] From 38d8b0d1b3e8cf66c745c41ab7bf5c14b117715e Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Thu, 22 Aug 2024 10:56:38 -0500 Subject: [PATCH 34/35] update Signed-off-by: Joe McCain III --- core/src/actors/actor.rs | 44 +---- core/src/actors/exec.rs | 33 ++-- core/src/macros/fmt.rs | 4 +- core/src/rules/builders/instructions.rs | 10 ++ core/src/rules/mod.rs | 31 +++- core/src/rules/program.rs | 24 +-- core/src/rules/rule.rs | 105 +++++++++++- core/src/rules/workload.rs | 216 ++++++++++++++++++++++++ core/src/state/mod.rs | 4 +- core/src/types/tail.rs | 24 +++ rstm/examples/actor.rs | 3 +- rstm/src/turing.rs | 2 +- 12 files changed, 415 insertions(+), 85 deletions(-) create mode 100644 core/src/rules/builders/instructions.rs create mode 100644 core/src/rules/workload.rs diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index baf8042..6a97c7a 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -7,7 +7,7 @@ pub use self::builder::ActorBuilder; use super::Executor; use crate::rules::Program; -use crate::{Direction, Error, Head, State}; +use crate::{Direction, Error, Head, State, Tail}; /// An [Actor] describes a Turing machine with a moving head (TMH). /// @@ -18,8 +18,6 @@ pub struct Actor { pub(crate) alpha: Vec, /// the head of the tape pub(crate) head: Head, - /// the number of steps taken by the actor - pub(crate) steps: usize, } impl Actor { @@ -35,7 +33,6 @@ impl Actor { state: State(state), symbol: 0, }, - steps: 0, } } @@ -76,10 +73,6 @@ impl Actor { pub fn state_mut(&mut self) -> State<&mut Q> { self.head.state_mut() } - /// Returns the number of steps taken by the actor - pub fn steps(&self) -> usize { - self.steps - } /// Executes the given program; the method is lazy, meaning it will not compute immediately /// but will return an [Executor] that is better suited for managing the runtime. pub fn execute(self, program: Program) -> Executor { @@ -139,11 +132,10 @@ impl Actor { #[cfg(feature = "tracing")] tracing::trace!("Writing to the tape..."); let pos = self.position(); - + if pos == usize::MAX { #[cfg(feature = "tracing")] tracing::trace!("Prepending to the tape..."); - } else if pos >= self.len() { #[cfg(feature = "tracing")] tracing::trace!("Appending to the tape..."); @@ -169,36 +161,9 @@ impl Actor { symbol: direction.apply(self.head.symbol), }; } - /// Performs a single step of the Turing machine - #[cfg_attr( - feature = "tracing", - tracing::instrument(skip_all, name = "step", target = "actor") - )] - pub(crate) fn step( - &mut self, - direction: Direction, - State(state): State, - symbol: S, - ) -> Result, Error> - where - S: Clone, - { - #[cfg(feature = "tracing")] - tracing::trace!("Transitioning the actor..."); - - // write the symbol to the tape - self.write(symbol); - // update the head of the actor - self.head = Head { - state: State(state), - symbol: direction.apply(self.head.symbol), - }; - // read the tape - self.read() - } - fn on_update(&mut self) { - self.steps += 1; + pub(crate) fn process(&mut self, rule: Tail) { + self.handle(rule.direction, rule.state, rule.symbol); } } @@ -298,7 +263,6 @@ mod builder { state: state.unwrap_or_default(), symbol, }, - steps: 0, } } } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index 5cd336c..ad75797 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -14,7 +14,11 @@ pub struct Executor { impl Executor { pub(crate) fn new(actor: Actor, program: Program) -> Self { - Self { actor, program, steps: 0 } + Self { + actor, + program, + steps: 0, + } } pub fn from_actor(actor: Actor) -> Self @@ -35,9 +39,13 @@ impl Executor { Executor { program, ..self } } - pub fn actor(&self) -> &Actor { + pub const fn actor(&self) -> &Actor { &self.actor } + /// Reads the current symbol at the head of the tape + pub fn read(&self) -> Result, Error> { + self.actor.read() + } #[cfg_attr( feature = "tracing", @@ -78,20 +86,21 @@ where #[cfg(feature = "tracing")] tracing::warn!("Detected a halted state; terminating the program..."); return None; - } + } // read the tape - let head = Head { state: self.actor.state().cloned(), symbol: self.actor.get().copied().unwrap_or_default() }; + let head = if let Ok(cur) = self.read() { + cur.cloned() + } else { + #[cfg(feature = "tracing")] + tracing::warn!("Unable to locate the value of the head..."); + Head::from_state(self.actor.state().cloned()) + }; // execute the program - if let Some(tail) = self - .program - .get_head_ref(head.to_ref()) { - // get the next head - let next = tail.cloned().into_head(); + if let Some(tail) = self.program.get(&head).cloned() { // process the instruction - self.actor - .handle(tail.direction(), tail.state.cloned(), *tail.symbol); + self.actor.process(tail.clone()); // return the head - return Some(next); + return Some(tail.into_head()); } else { #[cfg(feature = "tracing")] tracing::error!("No symbol found at {}", self.actor.position()); diff --git a/core/src/macros/fmt.rs b/core/src/macros/fmt.rs index a6f07dd..a588e45 100644 --- a/core/src/macros/fmt.rs +++ b/core/src/macros/fmt.rs @@ -5,9 +5,9 @@ macro_rules! unit_impl_fmt { ($trait:ident::<$T:ty>($fmt:expr)) => { - impl core::fmt::$trait for $T { + impl ::core::fmt::$trait for $T { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - $fmt(&self, f) + write!(f, $e, $fmt(self)) } } }; diff --git a/core/src/rules/builders/instructions.rs b/core/src/rules/builders/instructions.rs new file mode 100644 index 0000000..a5182a9 --- /dev/null +++ b/core/src/rules/builders/instructions.rs @@ -0,0 +1,10 @@ +/* + Appellation: instructions + Contrib: FL03 +*/ + +#[derive(Default)] +pub struct RulesetBuilder { + pub(crate) initial_state: Option>, + pub(crate) rules: Vec>, +} \ No newline at end of file diff --git a/core/src/rules/mod.rs b/core/src/rules/mod.rs index 5c2e822..bdd22b8 100644 --- a/core/src/rules/mod.rs +++ b/core/src/rules/mod.rs @@ -12,6 +12,8 @@ pub use self::{ pub(crate) mod program; pub(crate) mod rule; +pub mod workload; + #[doc(hidden)] pub(crate) mod builders { pub use self::{program::ProgramBuilder, rule::RuleBuilder}; @@ -26,12 +28,9 @@ pub(crate) mod prelude { pub use super::{Directive, Scope, Transition}; } -use crate::{Direction, State, Symbolic}; +use crate::{Direction, Head, State, Symbolic, Tail}; -pub trait Transition -where - S: Symbolic, -{ +pub trait Transition { fn direction(&self) -> Direction; fn current_state(&self) -> State<&'_ Q>; @@ -41,6 +40,28 @@ where fn symbol(&self) -> &S; fn write_symbol(&self) -> &S; + + fn head(&self) -> Head<&Q, &S> { + Head { + state: self.current_state(), + symbol: self.symbol(), + } + } + + fn tail(&self) -> Tail<&Q, &S> { + Tail { + direction: self.direction(), + state: self.next_state(), + symbol: self.write_symbol(), + } + } + + fn as_rule(&self) -> Rule<&Q, &S> { + Rule { + head: self.head(), + tail: self.tail(), + } + } } /// The [`Scope`] trait is used to describe objects containing information or references to the diff --git a/core/src/rules/program.rs b/core/src/rules/program.rs index 8209282..99fa028 100644 --- a/core/src/rules/program.rs +++ b/core/src/rules/program.rs @@ -72,22 +72,8 @@ impl Program { pub fn iter_mut(&mut self) -> core::slice::IterMut> { self.rules.iter_mut() } - - pub fn get(&self, State(state): State<&Q>, symbol: &S) -> Option<&Tail> - where - Q: PartialEq, - S: PartialEq, - { - self.iter().find_map(|i| { - if i.head_ref() == Head::new(State(state), symbol) { - Some(i.tail()) - } else { - None - } - }) - } /// Returns a collection of tails for a given head. - pub fn get_head(&self, head: &Head) -> Option<&Tail> + pub fn get(&self, head: &Head) -> Option<&Tail> where Q: PartialEq, S: PartialEq, @@ -100,8 +86,8 @@ impl Program { } }) } - - pub fn get_head_mut(&mut self, head: &Head) -> Option<&mut Tail> + /// Returns a mutable collection of tails for a given head. + pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> where Q: PartialEq, S: PartialEq, @@ -115,7 +101,7 @@ impl Program { }) } /// Returns a collection of tails for a given head. - pub fn get_head_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> + pub fn get_ref(&self, head: Head<&'_ Q, &'_ S>) -> Option> where Q: PartialEq, S: PartialEq, @@ -164,7 +150,7 @@ where type Output = Tail; fn index(&self, index: Head) -> &Self::Output { - self.get_head(&index).unwrap() + self.get(&index).unwrap() } } diff --git a/core/src/rules/rule.rs b/core/src/rules/rule.rs index 32cf33b..289a39b 100644 --- a/core/src/rules/rule.rs +++ b/core/src/rules/rule.rs @@ -37,7 +37,7 @@ impl Rule { pub fn tail_mut(&mut self) -> &mut Tail { &mut self.tail } - + /// Returns an instance of the [Tail] whose elements are immutable references pub fn tail_ref(&self) -> Tail<&'_ Q, &'_ S> { self.tail().to_ref() } @@ -45,17 +45,22 @@ impl Rule { pub fn direction(&self) -> Direction { self.tail().direction() } - /// Returns the current [state](State) of the [head](Head) + /// Returns the current [State] of the system pub fn state(&self) -> State<&'_ Q> { self.head().state() } - /// Returns the current symbol of the [head](Head) + /// Returns the symbol of the [Head] pub const fn symbol(&self) -> &S { self.head().symbol() } + /// Returns the next [Head] of the system pub fn next_head(&self) -> Head<&'_ Q, &'_ S> { self.tail().to_head_ref() } + /// Consumes the current object and returns the next [Head] of the system + pub fn into_next_head(self) -> Head { + self.tail.into_head() + } /// Returns the next [State] of the system pub fn next_state(&self) -> State<&'_ Q> { self.tail().state() @@ -64,4 +69,98 @@ impl Rule { pub const fn write_symbol(&self) -> &S { self.tail().symbol() } + /// Consumes the current object and returns a 2-tuple consisting of the [Head] and [Tail] + pub fn into_tuple(self) -> (Head, Tail) { + (self.head, self.tail) + } +} + +impl<'a, Q, S> Rule<&'a Q, &'a S> { + pub fn cloned(&self) -> Rule + where + Q: Clone, + S: Clone, + { + Rule { + head: self.head.cloned(), + tail: self.tail.cloned(), + } + } + + pub fn copied(&self) -> Rule + where + Q: Copy, + S: Copy, + { + Rule { + head: self.head.copied(), + tail: self.tail.copied(), + } + } +} + +impl core::convert::AsRef> for Rule { + fn as_ref(&self) -> &Head { + self.head() + } +} + +impl core::convert::AsRef> for Rule { + fn as_ref(&self) -> &Tail { + self.tail() + } +} + +impl core::convert::AsMut> for Rule { + fn as_mut(&mut self) -> &mut Head { + self.head_mut() + } +} + +impl core::convert::AsMut> for Rule { + fn as_mut(&mut self) -> &mut Tail { + self.tail_mut() + } +} + +impl core::borrow::Borrow> for Rule { + fn borrow(&self) -> &Head { + self.head() + } +} + +impl core::borrow::Borrow> for Rule { + fn borrow(&self) -> &Tail { + self.tail() + } +} + +impl core::borrow::BorrowMut> for Rule { + fn borrow_mut(&mut self) -> &mut Head { + self.head_mut() + } +} + +impl core::borrow::BorrowMut> for Rule { + fn borrow_mut(&mut self) -> &mut Tail { + self.tail_mut() + } +} + +impl From<(Head, Tail)> for Rule { + fn from((head, tail): (Head, Tail)) -> Self { + Self { head, tail } + } +} + +impl From> for (Head, Tail) { + fn from(rule: Rule) -> Self { + (rule.head, rule.tail) + } +} + +impl From> for Rule { + fn from(builder: RuleBuilder) -> Self { + builder.build() + } } diff --git a/core/src/rules/workload.rs b/core/src/rules/workload.rs new file mode 100644 index 0000000..b89cd0b --- /dev/null +++ b/core/src/rules/workload.rs @@ -0,0 +1,216 @@ +/* + Appellation: workload + Contrib: FL03 +*/ +// #![cfg(feature = "std")] +use super::Rule; +use crate::{Head, State, Tail}; +use std::collections::HashMap; + +pub struct RuleSet { + pub(crate) initial_state: State, + pub(crate) rules: HashMap, Tail>, +} + +impl RuleSet { + pub fn new() -> Self + where + Q: Default, + { + Self { + initial_state: State::default(), + rules: HashMap::new(), + } + } + + pub fn from_state(State(initial_state): State) -> Self { + Self { + initial_state: State(initial_state), + rules: HashMap::new(), + } + } + + pub fn with_initial_state(self, State(state): State) -> Self { + Self { + initial_state: State(state), + ..self + } + } + /// Returns an instance of [State] which owns a reference to the interval value. + pub fn initial_state(&self) -> State<&'_ Q> { + self.initial_state.to_ref() + } + /// Returns an immutable reference to the set of rules. + pub const fn rules(&self) -> &HashMap, Tail> { + &self.rules + } + /// Returns a mutable reference to the set of rules. + pub fn rules_mut(&mut self) -> &mut HashMap, Tail> { + &mut self.rules + } +} + +impl RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + pub fn from_iter(iter: I) -> Self + where + Q: Default, + I: IntoIterator, Tail)>, + { + Self { + initial_state: State::default(), + rules: HashMap::from_iter(iter), + } + } + + pub fn from_rules(iter: I) -> Self + where + Q: Default, + I: IntoIterator>, + { + let mut rules = HashMap::new(); + for rule in iter { + rules.insert(rule.head, rule.tail); + } + Self { + initial_state: State::default(), + rules, + } + } + + pub fn with_instructions( + self, + instructions: impl IntoIterator, Tail)>, + ) -> Self { + let mut rules = HashMap::new(); + for (head, tail) in instructions { + rules.insert(head, tail); + } + Self { rules, ..self } + } + /// Clears the set of rules. + pub fn clear(&mut self) { + self.rules.clear(); + } + /// Returns an immutable reference to the tail of the rule for the given head; returns none + /// if the head is not found. + pub fn get(&self, head: &Head) -> Option<&Tail> { + self.rules.get(head) + } + /// Returns a mutable reference to the tail of the rule for the given head; returns none if + /// the head is not found. + pub fn get_mut(&mut self, head: &Head) -> Option<&mut Tail> { + self.rules.get_mut(head) + } + /// Returns the tail of the rule for the given head; returns none if the head is not found + /// within the set of rules. + pub fn get_ref(&self, head: &Head) -> Option> { + self.get(head).map(|tail| tail.to_ref()) + } + /// Inserts a new rule into the set of rules. + pub fn insert(&mut self, head: Head, tail: Tail) { + self.rules.insert(head, tail); + } + /// Inserts a new rule into the set of rules. + pub fn insert_rule(&mut self, rule: Rule) { + self.insert(rule.head, rule.tail); + } + /// Returns true if the set of rules is empty. + pub fn is_empty(&self) -> bool { + self.rules.is_empty() + } + /// Returns the number of rules in the set. + pub fn len(&self) -> usize { + self.rules.len() + } + /// Removes a rule from the set of rules. + pub fn remove(&mut self, head: &Head) -> Option> { + self.rules.remove(head) + } +} + +impl core::iter::Extend<(Head, Tail)> for RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, Tail)>, + { + for (head, tail) in iter { + self.insert(head, tail); + } + } +} + +impl core::iter::Extend> for RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator>, + { + for rule in iter { + self.insert(rule.head, rule.tail); + } + } +} + +impl core::iter::FromIterator<(Head, Tail)> for RuleSet +where + Q: Default + Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + fn from_iter(iter: I) -> Self + where + I: IntoIterator, Tail)>, + { + Self::from_iter(iter) + } +} + +impl core::iter::FromIterator> for RuleSet +where + Q: Default + Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + fn from_iter(iter: I) -> Self + where + I: IntoIterator>, + { + Self::from_rules(iter) + } +} + +impl core::iter::IntoIterator for RuleSet { + type Item = (Head, Tail); + type IntoIter = std::collections::hash_map::IntoIter, Tail>; + + fn into_iter(self) -> Self::IntoIter { + self.rules.into_iter() + } +} + +impl<'a, Q, S> core::iter::IntoIterator for &'a RuleSet { + type Item = (&'a Head, &'a Tail); + type IntoIter = std::collections::hash_map::Iter<'a, Head, Tail>; + + fn into_iter(self) -> Self::IntoIter { + self.rules.iter() + } +} + +impl<'a, Q, S> core::iter::IntoIterator for &'a mut RuleSet { + type Item = (&'a Head, &'a mut Tail); + type IntoIter = std::collections::hash_map::IterMut<'a, Head, Tail>; + + fn into_iter(self) -> Self::IntoIter { + self.rules.iter_mut() + } +} diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index 24f8460..f255b89 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -22,7 +22,9 @@ pub(crate) mod prelude { pub use super::states::*; } -pub type AnyState = State>; +pub type AnyState = State>; + +pub trait BaseState: Eq + PartialOrd + core::hash::Hash {} #[doc(hidden)] pub trait RawState { diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 5dd860a..4f389e8 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -121,6 +121,18 @@ impl<'a, Q, S> Tail<&'a Q, &'a S> { symbol: self.symbol.clone(), } } + + pub fn copied(&self) -> Tail + where + Q: Copy, + S: Copy, + { + Tail { + direction: self.direction, + state: self.state.copied(), + symbol: *self.symbol, + } + } } impl<'a, Q, S> Tail<&'a mut Q, &'a mut S> { @@ -135,6 +147,18 @@ impl<'a, Q, S> Tail<&'a mut Q, &'a mut S> { symbol: self.symbol.clone(), } } + + pub fn copied(&self) -> Tail + where + Q: Copy, + S: Copy, + { + Tail { + direction: self.direction, + state: self.state.copied(), + symbol: *self.symbol, + } + } } mod builder { diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index 3507cba..e6c738e 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -29,8 +29,7 @@ fn main() -> Result<(), Box> { // create a new instance of the machine let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); - let out = tm.execute(program).run()?; - println!("Output: {out:?}"); + tm.execute(program).run()?; Ok(()) } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 8a4800b..4daa6f3 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -114,7 +114,7 @@ impl TM { direction, state, symbol, - }) = self.program.get_head_ref(self.read()?) + }) = self.program.get_ref(self.read()?) { // self.tape.update(direction, symbol.clone()); From 1de710f47e6ec679cafe8510d6abc71049a99fb0 Mon Sep 17 00:00:00 2001 From: Joe McCain III Date: Fri, 23 Aug 2024 13:00:31 -0500 Subject: [PATCH 35/35] update Signed-off-by: Joe McCain III --- .github/ISSUE_TEMPLATE/bug_report.md | 24 +-- .github/ISSUE_TEMPLATE/feature_request.md | 7 +- .github/ISSUE_TEMPLATE/issue.md | 2 +- .github/ISSUE_TEMPLATE/proposal.md | 7 +- .github/workflows/clippy.yml | 5 + .github/workflows/crates.yml | 2 +- .github/workflows/rust.yml | 15 +- README.md | 96 ++++++++--- SECURITY.md | 4 +- core/Cargo.toml | 15 +- core/src/actors/actor.rs | 2 +- core/src/actors/exec.rs | 1 + core/src/lib.rs | 7 +- core/src/rules/workload.rs | 116 +++++++++---- core/src/{types => shift}/direction.rs | 57 ++++--- core/src/shift/mod.rs | 45 +++++ core/src/state/halt/mod.rs | 2 +- core/src/state/halt/state.rs | 4 +- core/src/state/halt/wrap.rs | 63 ++++--- core/src/state/mod.rs | 6 +- core/src/tape/hash_tape.rs | 104 ++++++++++++ core/src/tape/mod.rs | 115 ++++++++++++- core/src/tape/tape.rs | 50 +++--- core/src/traits/increment.rs | 73 ++++++++ core/src/traits/mod.rs | 10 +- core/src/types/cursor.rs | 193 ++++++++++++++++++++++ core/src/types/head.rs | 31 +++- core/src/types/mod.rs | 14 +- core/src/types/tail.rs | 41 ++++- core/tests/actor.rs | 5 +- rstm/examples/actor.rs | 12 +- rstm/examples/basic.rs | 6 +- rstm/src/lib.rs | 4 +- rstm/src/turing.rs | 34 ++-- rstm/src/turing/model.rs | 13 -- rstm/src/turing/state.rs | 48 ------ 36 files changed, 954 insertions(+), 279 deletions(-) rename core/src/{types => shift}/direction.rs (85%) create mode 100644 core/src/shift/mod.rs create mode 100644 core/src/tape/hash_tape.rs create mode 100644 core/src/traits/increment.rs create mode 100644 core/src/types/cursor.rs delete mode 100644 rstm/src/turing/model.rs delete mode 100644 rstm/src/turing/state.rs diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..c5b743a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,9 +1,10 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: '' -assignees: '' +assignees: [ FL03 ] +labels: [ bug ] +projects: [ '@FL03/rstm:dev' ] +title: 'Bug: ' --- @@ -12,6 +13,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +26,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..43525e8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,9 +1,10 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' +assignees: [ FL03 ] +labels: [ enhancement ] +projects: [ '@FL03/rstm:dev' ] +title: 'Feature Request: ' --- diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md index 925cfed..66eb978 100644 --- a/.github/ISSUE_TEMPLATE/issue.md +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -3,7 +3,7 @@ about: A generic issue template assignees: - FL03 labels: [] -projects: ['@FL03/concision:features'] +projects: ['@FL03/rstm:dev'] name: Generic Issue title: '' --- diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md index 5b35200..37e764b 100644 --- a/.github/ISSUE_TEMPLATE/proposal.md +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -1,10 +1,9 @@ --- about: A formal proposal discussing any new features, changes, or improvements to the project. -assignees: - - FL03 -labels: ['proposal'] +assignees: [ FL03 ] +labels: [ 'proposal' ] name: Improvement Proposal -title: 'CNC-0000:' +title: 'Proposal: ' --- diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 83ba4e2..39d0006 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -1,9 +1,14 @@ name: clippy +concurrency: + cancel-in-progress: false + group: ${{ github.workflow }}-${{ github.ref }} + on: pull_request: branches: [ main ] release: + types: [ created ] repository_dispatch: types: [ clippy ] schedule: diff --git a/.github/workflows/crates.yml b/.github/workflows/crates.yml index 0fb4898..e9c761d 100644 --- a/.github/workflows/crates.yml +++ b/.github/workflows/crates.yml @@ -1,8 +1,8 @@ name: crates concurrency: - group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false + group: ${{ github.workflow }}-${{ github.ref }} env: BASENAME: ${{ github.event.repository.name }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0ccfc7d..932548a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,8 +1,8 @@ name: rust -concurrency: +concurrency: cancel-in-progress: false - group: ${{ github.event.repository.name }}-rust + group: ${{ github.workflow }}-${{ github.ref }} env: CARGO_TERM_COLOR: always @@ -12,10 +12,9 @@ on: pull_request: branches: [ main ] push: - branches: [ main ] tags: [ v*.*.* ] release: - types: [ created ] + types: [ published ] repository_dispatch: types: [ rust ] schedule: @@ -53,9 +52,9 @@ jobs: cargo-${{ matrix.toolchain }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} cargo-${{ matrix.toolchain }}-${{ runner.os }}- cargo-${{ matrix.toolchain }}- - cargo- + - name: cargo test (workspace) --full + run: cargo test -v --workspace -F full - name: cargo (bench) if: matrix.toolchain == 'nightly' - run: cargo bench --features full -v --workspace - - name: cargo test (workspace)[full] - run: cargo test -v --workspace -F full + run: cargo bench -F full -v --workspace + diff --git a/README.md b/README.md index 7ac538d..270d810 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,23 @@ # rstm + [![crates.io](https://img.shields.io/crates/v/rstm.svg)](https://crates.io/crates/rstm) [![docs.rs](https://docs.rs/rstm/badge.svg)](https://docs.rs/rstm) - [![clippy](https://github.com/FL03/rstm/actions/workflows/clippy.yml/badge.svg)](https://github.com/FL03/rstm/actions/workflows/clippy.yml) [![rust](https://github.com/FL03/rstm/actions/workflows/rust.yml/badge.svg)](https://github.com/FL03/rstm/actions/workflows/rust.yml) -*** - -### _The library is currently in the early stages of development and is not yet ready for production use._ +[![license](https://img.shields.io/crates/l/rstm.svg)](https://crates.io/crates/rstm) +[![lines of code](https://tokei.rs/b1/github/FL03/rstm?category=code)](https://tokei.rs/b1/github/FL03/rstm?category=code) -This library focuses on building concrete implementations for Turing Machines. - -## Features +*** +_**The library is currently in the early stages of development and is still settling in on a feel for the api.**_ +This library focuses on building concrete implementations for Turing Machines. ## Getting Started -### Building from the source +### From the source Start by cloning the repository @@ -28,47 +27,90 @@ cd rstm ``` ```bash -cargo build --features full -r --workspace +cargo build --all-features --workspace +``` + +#### _Run an example_ + +```bash +cargo run -f F --example actor ``` ## Usage -### Example +### Creating a new ruleset + +Programs are essentially collections of rules that define the behavior of the machine. Facilitating the creation of these rules is the `ruleset!` macro. The macro allows developers to define a set of rules for the machine in a concise and readable manner while further emulating the transition function defined by "On topological dynamics of Turing machines" by Petr Kůrka; `δ: Q x A -> Q x A x {-1, 0, 1}.` + + +`ruleset!` is a macro that allows you to define a set of rules for the machine. The syntax is as follows: + +```rust + ruleset![ + (state, symbol) -> Direction(next_state, next_symbol), + ... + ] +``` + +The macro is hygenic, meaning developers will not need to import the `Direction` enum nor its variants in order to use the macro. + + + +#### Example: Building a ruleset for a three-state, two-symbol Turing machine + +```rust + use rstm::ruleset; + + // define the ruleset for the machine + let rules = ruleset![ + (0, 0) -> Right(1, 0), + (0, 1) -> Stay(-1, 1), + (1, 0) -> Left(0, 1), + (1, 1) -> Right(-1, 0), + (-1, 0) -> Right(0, 0), + (-1, 1) -> Right(1, 1), + ]; +``` + +### Examples ```rust extern crate rstm; - use rstm::state::BinState::{Invalid, Valid}; - use rstm::{rule, Program, State, StdTape, TM}; + use rstm::{ruleset, Actor, Program, State}; fn main() -> Result<(), Box> { tracing_subscriber::fmt().with_target(false).init(); // initialize the tape data - let alpha: Vec = vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]; - // define the rules for the machine - let rules = vec![ - rule![(Invalid, 0) -> Right(Invalid, 0)], - rule![(Invalid, 1) -> Right(Valid, 0)], - rule![(Valid, 0) -> Right(Valid, 1)], - rule![(Valid, 1) -> Left(Valid, 0)], + let alpha = vec![0i8; 10]; + // initialize the state of the machine + let initial_state = State(0); + // define the ruleset for the machine + let rules = ruleset![ + (0, 0) -> Right(1, 0), + (0, 1) -> Right(-1, 1), + (1, 0) -> Right(0, 1), + (1, 1) -> Right(-1, 0), + (-1, 0) -> Left(0, 0), + (-1, 1) -> Left(1, 1), ]; - let tape = StdTape::from_iter(alpha); - let program = Program::from_state(State(Invalid)).with_instructions(rules); + let program = Program::new() + .initial_state(initial_state) + .rules(rules) + .build(); + // create a new instance of the machine - let tm = TM::new(program, tape); - tm.execute()?; + let tm = dbg!(Actor::from_state(initial_state).with_tape(alpha)); + tm.execute(program).run()?; Ok(()) } ``` ## Contributing -Pull requests are welcome. For major changes, please open an issue first -to discuss what you would like to change. - -Please make sure to update tests as appropriate. +Pull requests are welcome. Any improvements or modifactions should first be disccussed using a pull-request and/or by opening an issue. Additionally, please make sure to update tests as appropriate and to adhear to the feature gates. ## License diff --git a/SECURITY.md b/SECURITY.md index f26a990..1e786d2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,6 +6,8 @@ Checkout the current and supported packages below | Package | Current | Supported | |---------|---------|-----------| -| rstm | 0.0.0 | <=0.0.0 | +| rstm | 0.0.3 | <=0.0.3 | ## Reporting a Vulnerability + +Any issues or vulnerabilities should be reported to the maintainer of the package via email or by creating an [issue](https://github.com/FL03/rstm/issues/new) on the repository. diff --git a/core/Cargo.toml b/core/Cargo.toml index 1cab80d..48eb54e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,21 +13,30 @@ repository.workspace = true version.workspace = true [features] -default = [] +default = [ + "alloc", +] full = [ "default", + "rand", "serde", "tracing", ] # ********* [FF] Dependencies ********* alloc = [ + "num/alloc", "serde?/alloc", ] +rand = [ + "num/rand", +] + serde = [ "dep:serde", + "num/serde", ] tracing = [ @@ -51,6 +60,10 @@ test = true thiserror.workspace = true paste.workspace = true +[dependencies.num] +# default-features = false +version = "0.4" + [dependencies.serde] # default-features = false features = ["derive"] diff --git a/core/src/actors/actor.rs b/core/src/actors/actor.rs index 6a97c7a..e0f6cb9 100644 --- a/core/src/actors/actor.rs +++ b/core/src/actors/actor.rs @@ -158,7 +158,7 @@ impl Actor { // update the head of the actor self.head = Head { state: State(state), - symbol: direction.apply(self.head.symbol), + symbol: direction.apply_unsigned(self.head.symbol), }; } diff --git a/core/src/actors/exec.rs b/core/src/actors/exec.rs index ad75797..3207ed9 100644 --- a/core/src/actors/exec.rs +++ b/core/src/actors/exec.rs @@ -5,6 +5,7 @@ use super::Actor; use crate::{Error, Head, Program, Symbolic}; +/// pub struct Executor { pub(crate) actor: Actor, pub(crate) program: Program, diff --git a/core/src/lib.rs b/core/src/lib.rs index eecac6b..0051933 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -14,9 +14,10 @@ pub use self::{ actors::Actor, error::Error, rules::{Program, Rule}, + shift::Direction, state::State, - tape::Tape, - traits::prelude::*, + tape::StdTape, + traits::*, types::prelude::*, }; @@ -37,6 +38,7 @@ pub(crate) mod seal; pub mod actors; pub mod error; pub mod rules; +pub mod shift; pub mod state; pub mod tape; pub mod traits; @@ -46,6 +48,7 @@ pub mod prelude { pub use crate::actors::prelude::*; pub use crate::error::Error; pub use crate::rules::prelude::*; + pub use crate::shift::prelude::*; pub use crate::state::prelude::*; pub use crate::tape::prelude::*; pub use crate::traits::prelude::*; diff --git a/core/src/rules/workload.rs b/core/src/rules/workload.rs index b89cd0b..a66d7d6 100644 --- a/core/src/rules/workload.rs +++ b/core/src/rules/workload.rs @@ -5,14 +5,24 @@ // #![cfg(feature = "std")] use super::Rule; use crate::{Head, State, Tail}; -use std::collections::HashMap; +use std::collections::hash_map::{self, HashMap}; -pub struct RuleSet { +#[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ pub(crate) initial_state: State, pub(crate) rules: HashMap, Tail>, } -impl RuleSet { +impl RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ pub fn new() -> Self where Q: Default, @@ -30,31 +40,6 @@ impl RuleSet { } } - pub fn with_initial_state(self, State(state): State) -> Self { - Self { - initial_state: State(state), - ..self - } - } - /// Returns an instance of [State] which owns a reference to the interval value. - pub fn initial_state(&self) -> State<&'_ Q> { - self.initial_state.to_ref() - } - /// Returns an immutable reference to the set of rules. - pub const fn rules(&self) -> &HashMap, Tail> { - &self.rules - } - /// Returns a mutable reference to the set of rules. - pub fn rules_mut(&mut self) -> &mut HashMap, Tail> { - &mut self.rules - } -} - -impl RuleSet -where - Q: Eq + core::hash::Hash, - S: Eq + core::hash::Hash, -{ pub fn from_iter(iter: I) -> Self where Q: Default, @@ -81,6 +66,13 @@ where } } + pub fn with_initial_state(self, State(state): State) -> Self { + Self { + initial_state: State(state), + ..self + } + } + pub fn with_instructions( self, instructions: impl IntoIterator, Tail)>, @@ -91,10 +83,26 @@ where } Self { rules, ..self } } + /// Returns an instance of [State] which owns a reference to the interval value. + pub fn initial_state(&self) -> State<&'_ Q> { + self.initial_state.to_ref() + } + /// Returns an immutable reference to the set of rules. + pub const fn rules(&self) -> &HashMap, Tail> { + &self.rules + } + /// Returns a mutable reference to the set of rules. + pub fn rules_mut(&mut self) -> &mut HashMap, Tail> { + &mut self.rules + } /// Clears the set of rules. pub fn clear(&mut self) { self.rules.clear(); } + /// Returns an the entry for the given head within the set of rules. + pub fn entry(&mut self, head: Head) -> hash_map::Entry, Tail> { + self.rules.entry(head) + } /// Returns an immutable reference to the tail of the rule for the given head; returns none /// if the head is not found. pub fn get(&self, head: &Head) -> Option<&Tail> { @@ -126,6 +134,28 @@ where pub fn len(&self) -> usize { self.rules.len() } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the + /// tail if the head is not found. + pub fn or_insert(&mut self, head: Head, tail: Tail) -> &mut Tail { + self.rules.entry(head).or_insert(tail) + } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the + /// tail if the head is not found. + pub fn or_insert_with(&mut self, head: Head, f: F) -> &mut Tail + where + F: FnOnce() -> Tail, + { + self.rules.entry(head).or_insert_with(f) + } + /// Returns a mutable reference to the tail of the rule for the given head; inserts the + /// default tail if the head is not found. + pub fn or_insert_default(&mut self, head: Head) -> &mut Tail + where + Q: Default, + S: Default, + { + self.or_insert(head, Tail::default()) + } /// Removes a rule from the set of rules. pub fn remove(&mut self, head: &Head) -> Option> { self.rules.remove(head) @@ -162,6 +192,18 @@ where } } +impl core::ops::Index> for RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ + type Output = Tail; + + fn index(&self, head: Head) -> &Self::Output { + &self.rules[&head] + } +} + impl core::iter::FromIterator<(Head, Tail)> for RuleSet where Q: Default + Eq + core::hash::Hash, @@ -188,7 +230,11 @@ where } } -impl core::iter::IntoIterator for RuleSet { +impl core::iter::IntoIterator for RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ type Item = (Head, Tail); type IntoIter = std::collections::hash_map::IntoIter, Tail>; @@ -197,7 +243,11 @@ impl core::iter::IntoIterator for RuleSet { } } -impl<'a, Q, S> core::iter::IntoIterator for &'a RuleSet { +impl<'a, Q, S> core::iter::IntoIterator for &'a RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ type Item = (&'a Head, &'a Tail); type IntoIter = std::collections::hash_map::Iter<'a, Head, Tail>; @@ -206,7 +256,11 @@ impl<'a, Q, S> core::iter::IntoIterator for &'a RuleSet { } } -impl<'a, Q, S> core::iter::IntoIterator for &'a mut RuleSet { +impl<'a, Q, S> core::iter::IntoIterator for &'a mut RuleSet +where + Q: Eq + core::hash::Hash, + S: Eq + core::hash::Hash, +{ type Item = (&'a Head, &'a mut Tail); type IntoIter = std::collections::hash_map::IterMut<'a, Head, Tail>; diff --git a/core/src/types/direction.rs b/core/src/shift/direction.rs similarity index 85% rename from core/src/types/direction.rs rename to core/src/shift/direction.rs index e4014f5..60ace26 100644 --- a/core/src/types/direction.rs +++ b/core/src/shift/direction.rs @@ -2,14 +2,6 @@ Appellation: direction Contrib: FL03 */ -/// The [AsDirection] trait provides a convience method for converting a type into a [Direction]. -pub trait AsDirection { - fn as_direction(&self) -> Direction; -} -/// The [IntoDirection] trait provides a convience method for converting a type into a [Direction]. -pub trait IntoDirection { - fn into_direction(self) -> Direction; -} /// [Direction] enumerates the various directions a head can move, namely: left, right, and stay. /// The included methods and implementations aim to streamline the conversion between [Direction] and other types. @@ -138,34 +130,61 @@ impl Direction { Self::Stay => "stay", } } + /// Applies the shift to the given position in the [direction](Direction) specified by the /// current instance. This is done using the [`wrapping_add_signed`](usize::wrapping_add_signed) /// method. - pub fn apply(self, cur: usize) -> usize { + pub fn apply_unsigned(self, cur: usize) -> usize { cur.wrapping_add_signed(self as isize) } } -impl AsDirection for T +impl core::ops::Add for Direction where - T: Clone + Into, + T: crate::Decrement + crate::Increment, { - fn as_direction(&self) -> Direction { - self.clone().into() + type Output = T; + + fn add(self, rhs: T) -> Self::Output { + match self { + Self::Left => rhs.decrement(), + Self::Right => rhs.increment(), + Self::Stay => rhs, + } } } -impl IntoDirection for T -where - T: Into, -{ - fn into_direction(self) -> Direction { - self.into() +impl core::ops::Add for isize { + type Output = isize; + + fn add(self, rhs: Direction) -> Self::Output { + self + rhs as isize + } +} + +impl core::ops::Add for usize { + type Output = usize; + + fn add(self, rhs: Direction) -> Self::Output { + self.wrapping_add_signed(rhs as isize) + } +} + +impl core::ops::AddAssign for usize { + fn add_assign(&mut self, rhs: Direction) { + *self = core::ops::Add::add(*self, rhs); + } +} + +impl core::ops::AddAssign for isize { + fn add_assign(&mut self, rhs: Direction) { + *self = core::ops::Add::add(*self, rhs); } } mod impl_from { use super::*; + use crate::shift::IntoDirection; macro_rules! impl_from_direction { ($($T:ident),*) => { diff --git a/core/src/shift/mod.rs b/core/src/shift/mod.rs new file mode 100644 index 0000000..7d7903b --- /dev/null +++ b/core/src/shift/mod.rs @@ -0,0 +1,45 @@ +/* + Appellation: shift + Contrib: FL03 +*/ +#[doc(inline)] +pub use self::direction::Direction; + +pub(crate) mod direction; + +pub(crate) mod prelude { + pub use super::direction::Direction; +} + +pub trait Directional { + fn direction(&self) -> Direction; +} +/// The [AsDirection] trait provides a convience method for converting a type into a [Direction]. +pub trait AsDirection { + fn as_direction(&self) -> Direction; +} +/// The [IntoDirection] trait provides a convience method for converting a type into a [Direction]. +pub trait IntoDirection { + fn into_direction(self) -> Direction; +} + +/* + ************* Implementations ************* +*/ +impl AsDirection for T +where + T: Clone + Into, +{ + fn as_direction(&self) -> Direction { + self.clone().into() + } +} + +impl IntoDirection for T +where + T: Into, +{ + fn into_direction(self) -> Direction { + self.into() + } +} diff --git a/core/src/state/halt/mod.rs b/core/src/state/halt/mod.rs index 76dc125..338b783 100644 --- a/core/src/state/halt/mod.rs +++ b/core/src/state/halt/mod.rs @@ -6,7 +6,7 @@ //! //! #[doc(inline)] -pub use self::{state::Halt, wrap::Halting}; +pub use self::{state::Halt, wrap::HaltState}; pub(crate) mod state; pub(crate) mod wrap; diff --git a/core/src/state/halt/state.rs b/core/src/state/halt/state.rs index e87033b..dd7162e 100644 --- a/core/src/state/halt/state.rs +++ b/core/src/state/halt/state.rs @@ -41,11 +41,11 @@ impl Halt { State(self) } /// Returns an instance of [`Halt`] with an immutable reference to the inner value. - pub fn view<'a>(&'a self) -> Halt<&'a Q> { + pub fn view(&self) -> Halt<&Q> { Halt(&self.0) } /// Returns an instance of [`Halt`] with a mutable reference to the inner value. - pub fn view_mut<'a>(&'a mut self) -> Halt<&'a mut Q> { + pub fn view_mut(&mut self) -> Halt<&mut Q> { Halt(&mut self.0) } } diff --git a/core/src/state/halt/wrap.rs b/core/src/state/halt/wrap.rs index 31146b1..6355915 100644 --- a/core/src/state/halt/wrap.rs +++ b/core/src/state/halt/wrap.rs @@ -4,66 +4,77 @@ */ use crate::state::{Halt, State}; -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum Halting { - Step(State), +/// [HaltState] extends the [State] by allowing for an 'imaginary' state that is not actually +/// part of the machine's state space. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, strum::EnumDiscriminants, strum::EnumIs,)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), strum_discriminants(derive(serde::Deserialize, serde::Serialize)))] +#[strum_discriminants(name(HaltTag), derive(Hash, Ord, PartialOrd))] +pub enum HaltState { Halt(Halt), + State(State), } -impl Halting { - pub fn is_halted(&self) -> bool { - match self { - Self::Halt(_) => true, - _ => false, - } +impl HaltState { + /// Creates a new instance of a [HaltState] with a halted state. + pub fn halt(Halt(state): Halt) -> Self { + Self::Halt(Halt(state)) } - - pub fn is_continuing(&self) -> bool { - match self { - Self::Step(_) => true, - _ => false, - } + /// Creates a new instance of a [HaltState] with a continuing state. + pub fn state(state: State) -> Self { + Self::State(state) } pub fn into_state(self) -> State { match self { - Self::Step(state) => state, + Self::State(state) => state, Self::Halt(halt) => State(halt.0), } } pub fn as_state(&self) -> State<&Q> { - match self { - Self::Step(state) => state.to_ref(), - Self::Halt(halt) => State(halt.view().0), - } + State(self.get()) + } + + pub fn as_mut_state(&mut self) -> State<&mut Q> { + State(self.get_mut()) } pub fn get(&self) -> &Q { match self { - Self::Step(inner) => inner.get(), + Self::State(inner) => inner.get(), Self::Halt(inner) => inner.get(), } } pub fn get_mut(&mut self) -> &mut Q { match self { - Self::Step(inner) => inner.get_mut(), + Self::State(inner) => inner.get_mut(), Self::Halt(inner) => inner.get_mut(), } } pub fn set(&mut self, state: Q) { match self { - Self::Step(inner) => inner.set(state), + Self::State(inner) => inner.set(state), Self::Halt(inner) => inner.set(state), } } } -impl Default for Halting { +impl Default for HaltState { fn default() -> Self { - Self::Step(State::default()) + Self::State(State::default()) } } + +impl From> for HaltState { + fn from(state: State) -> Self { + Self::State(state) + } +} + +impl From> for HaltState { + fn from(halt: Halt) -> Self { + Self::Halt(halt) + } +} \ No newline at end of file diff --git a/core/src/state/mod.rs b/core/src/state/mod.rs index f255b89..8683728 100644 --- a/core/src/state/mod.rs +++ b/core/src/state/mod.rs @@ -3,7 +3,7 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{halt::Halt, state::State, states::*}; +pub use self::{halt::*, state::State, states::*}; pub(crate) mod state; @@ -17,9 +17,10 @@ pub(crate) mod states { } pub(crate) mod prelude { - + pub use super::halt::*; pub use super::state::State; pub use super::states::*; + pub use super::AnyState; } pub type AnyState = State>; @@ -31,6 +32,7 @@ pub trait RawState { type Ctx; } +#[doc(hidden)] pub trait Stated: RawState { fn cloned(&self) -> Self where diff --git a/core/src/tape/hash_tape.rs b/core/src/tape/hash_tape.rs new file mode 100644 index 0000000..47d302d --- /dev/null +++ b/core/src/tape/hash_tape.rs @@ -0,0 +1,104 @@ +/* + Appellation: hash_tape + Contrib: FL03 +*/ +// #![cfg(feature = "std")] +use crate::shift::Direction; +use std::collections::hash_map::{self, HashMap}; + +pub trait HashIndex: Eq + core::hash::Hash + core::ops::Neg {} + +pub type Hdx = isize; + +#[derive(Clone, Debug, Default)] +pub struct HashTape { + cursor: Hdx, + store: HashMap, + ticks: usize, +} + +impl HashTape { + pub fn new() -> HashTape { + HashTape { + cursor: 0, + store: HashMap::new(), + ticks: 0, + } + } + + pub fn reset(&mut self) { + self.cursor = 0; + self.store.clear(); + self.ticks = 0; + } + + pub fn cursor(&self) -> Hdx { + self.cursor + } + + pub fn ticks(&self) -> usize { + self.ticks + } + + pub fn entry(&mut self, index: Hdx) -> hash_map::Entry { + self.store.entry(index) + } + + pub fn get(&self, index: Hdx) -> Option<&V> { + self.store.get(&index) + } + /// Returns a mutable reference to the value at the given index. + pub fn get_mut(&mut self, index: Hdx) -> Option<&mut V> { + self.store.get_mut(&index) + } + /// Inserts a value at the given index. + pub fn insert(&mut self, index: Hdx, value: V) { + self.store.insert(index, value); + } + /// Returns true if the tape is empty. + pub fn is_empty(&self) -> bool { + self.store.is_empty() + } + /// Returns the number of elements in the tape. + pub fn len(&self) -> usize { + self.store.len() + } + /// Removes the value at the given index. + pub fn remove(&mut self, index: Hdx) -> Option { + self.store.remove(&index) + } + /// Shifts the cursor in the given direction. + pub fn shift(&mut self, direction: Direction) { + self.cursor += direction; + self.ticks += 1; + } + /// Returns a mutable reference to the value of the head at the current position; on empty, + /// the given value is inserted and returned. + pub fn or_insert(&mut self, default: V) -> &mut V { + self.store.entry(self.cursor).or_insert(default) + } + /// Returns a mutable reference to the value of the head at the current position; on empty, + /// the function is evaluated and the result is inserted and returned. + pub fn or_insert_with(&mut self, default: F) -> &mut V + where + F: FnOnce() -> V, + { + self.store.entry(self.cursor).or_insert_with(default) + } + /// Returns a mutable reference to the value of the head at the current position; if the + /// value is not present, the default value is inserted and returned. + pub fn or_default(&mut self) -> &mut V + where + V: Default, + { + self.store.entry(self.cursor).or_default() + } + /// Returns a reference to the value at the current cursor position. + pub fn read(&self) -> Option<&V> { + self.store.get(&self.cursor) + } + + pub fn write(&mut self, value: V) { + let _ = self.store.insert(self.cursor, value); + } +} diff --git a/core/src/tape/mod.rs b/core/src/tape/mod.rs index 04452ad..3f52730 100644 --- a/core/src/tape/mod.rs +++ b/core/src/tape/mod.rs @@ -7,15 +7,38 @@ //! Idealized Turing machines consider a tape, or memory, that is infinite in both directions. //! This tape is a one-dimensional array of symbols manipulated by the tape head according to //! some set of pre-defined rules. -pub use self::tape::Tape; +pub use self::tape::StdTape; pub(crate) mod tape; +#[doc(hidden)] +pub mod hash_tape; + pub(crate) mod prelude { - pub use super::tape::Tape; + pub use super::tape::StdTape; } -/// [RawTape] is a trait that provides a common interface for tape-like structures. +#[doc(hidden)] +pub trait Mem { + type Key; + type Value; + + fn clear(&mut self); + + fn get(&self, key: &Self::Key) -> Option<&Self::Value>; + + fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value>; + + fn insert(&mut self, key: Self::Key, value: Self::Value); + + fn is_empty(&self) -> bool; + + fn len(&self) -> usize; +} + +#[doc(hidden)] +/// [RawTape] defines the basic interface used for tape-like structures; i.e., a contiguous, +/// sequential array of elements. pub trait RawTape { type Elem; @@ -32,9 +55,27 @@ pub trait RawTape { } } +#[doc(hidden)] +/// [Tape] is a +pub trait Tape: RawTape { + type Idx; + + fn clear(&mut self); + + fn get(&self, idx: &Self::Idx) -> Option<&Self::Elem>; + + fn get_mut(&mut self, idx: &Self::Idx) -> Option<&mut Self::Elem>; + + fn insert(&mut self, idx: Self::Idx, elem: Self::Elem); +} + /* ************* Implementations ************* */ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use std::collections::HashMap; + impl RawTape for [T] { type Elem = T; @@ -70,3 +111,71 @@ impl RawTape for Vec { Vec::len(self) } } + +impl Mem for Vec { + type Key = usize; + type Value = V; + + fn clear(&mut self) { + Vec::clear(self); + } + + fn get(&self, key: &Self::Key) -> Option<&Self::Value> { + match key { + key if *key < self.len() => Some(&self[*key]), + _ => None, + } + } + + fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> { + match key { + key if *key < self.len() => Some(&mut self[*key]), + _ => None, + } + } + + fn insert(&mut self, key: Self::Key, value: Self::Value) { + Vec::insert(self, key, value); + } + + fn is_empty(&self) -> bool { + Vec::is_empty(self) + } + + fn len(&self) -> usize { + Vec::len(self) + } +} + +impl Mem for HashMap +where + K: Eq + std::hash::Hash, + V: Eq + std::hash::Hash, +{ + type Key = K; + type Value = V; + + fn clear(&mut self) { + HashMap::clear(self); + } + + fn get(&self, key: &Self::Key) -> Option<&Self::Value> { + HashMap::get(self, key) + } + + fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> { + HashMap::get_mut(self, &key) + } + + fn insert(&mut self, key: Self::Key, value: Self::Value) { + HashMap::insert(self, key, value); + } + + fn is_empty(&self) -> bool { + HashMap::is_empty(self) + } + + fn len(&self) -> usize { + HashMap::len(self) + } +} diff --git a/core/src/tape/tape.rs b/core/src/tape/tape.rs index 84b7c37..2bf1c58 100644 --- a/core/src/tape/tape.rs +++ b/core/src/tape/tape.rs @@ -8,7 +8,7 @@ use core::cell::Cell; #[cfg(feature = "alloc")] use alloc::vec::Vec; -/// In-line with the Turing machine model, the [`Tape`] is a one-dimensional surface evenly +/// In-line with the Turing machine model, the [`StdTape`] is a one-dimensional surface evenly /// divided into cells capable of storing symbols. The tape is infinite in both directions /// allowing the head, or actor, to move without bounds, extending the tape as needed. /// @@ -23,15 +23,15 @@ use alloc::vec::Vec; /// is an operation that does result in some change in-time. #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct Tape { +pub struct StdTape { cursor: usize, store: Vec, ticks: Cell, } -impl Tape { +impl StdTape { pub fn new() -> Self { - Tape { + StdTape { cursor: 0, store: Vec::::new(), ticks: Cell::default(), @@ -39,7 +39,7 @@ impl Tape { } /// Constructs a new tape from an iterator. pub fn from_iter(iter: impl IntoIterator) -> Self { - Tape { + StdTape { cursor: 0, store: Vec::from_iter(iter), ticks: Cell::default(), @@ -47,7 +47,7 @@ impl Tape { } /// Constructs a new, empty tape with the specified capacity. pub fn with_capacity(capacity: usize) -> Self { - Tape { + StdTape { cursor: 0, store: Vec::::with_capacity(capacity), ticks: Cell::default(), @@ -139,18 +139,18 @@ impl Tape { } fn on_update(&self) { - self.ticks.set(self.ticks.get() + 1); + self.ticks.set(self.ticks() + 1); } fn shift(&mut self, direction: Direction) -> usize { - self.cursor = direction.apply(self.cursor) % self.store.len(); + self.cursor = direction.apply_unsigned(self.cursor) % self.store.len(); self.position() } } -impl Tape { - pub fn from_str(input: &str) -> Tape { - Tape { +impl StdTape { + pub fn from_str(input: &str) -> StdTape { + StdTape { cursor: 0, store: input.chars().collect(), ticks: Cell::default(), @@ -158,31 +158,31 @@ impl Tape { } } -impl AsRef<[S]> for Tape { +impl AsRef<[S]> for StdTape { fn as_ref(&self) -> &[S] { &self.store } } -impl AsMut<[S]> for Tape { +impl AsMut<[S]> for StdTape { fn as_mut(&mut self) -> &mut [S] { &mut self.store } } -impl core::borrow::Borrow<[S]> for Tape { +impl core::borrow::Borrow<[S]> for StdTape { fn borrow(&self) -> &[S] { &self.store } } -impl core::borrow::BorrowMut<[S]> for Tape { +impl core::borrow::BorrowMut<[S]> for StdTape { fn borrow_mut(&mut self) -> &mut [S] { &mut self.store } } -impl core::ops::Deref for Tape { +impl core::ops::Deref for StdTape { type Target = [S]; fn deref(&self) -> &Self::Target { @@ -190,13 +190,13 @@ impl core::ops::Deref for Tape { } } -impl core::ops::DerefMut for Tape { +impl core::ops::DerefMut for StdTape { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.store } } -impl core::fmt::Debug for Tape +impl core::fmt::Debug for StdTape where S: core::fmt::Debug, { @@ -211,7 +211,7 @@ where } } -impl core::fmt::Display for Tape +impl core::fmt::Display for StdTape where S: core::fmt::Display, { @@ -226,7 +226,7 @@ where } } -impl core::iter::Extend for Tape { +impl core::iter::Extend for StdTape { fn extend(&mut self, iter: T) where T: IntoIterator, @@ -235,16 +235,16 @@ impl core::iter::Extend for Tape { } } -impl core::iter::FromIterator for Tape { +impl core::iter::FromIterator for StdTape { fn from_iter(iter: I) -> Self where I: IntoIterator, { - Tape::from_iter(iter) + StdTape::from_iter(iter) } } -impl core::iter::IntoIterator for Tape { +impl core::iter::IntoIterator for StdTape { type Item = S; type IntoIter = std::vec::IntoIter; @@ -253,7 +253,7 @@ impl core::iter::IntoIterator for Tape { } } -impl core::ops::Index for Tape +impl core::ops::Index for StdTape where I: core::slice::SliceIndex<[S]>, { @@ -264,7 +264,7 @@ where } } -impl core::ops::IndexMut for Tape +impl core::ops::IndexMut for StdTape where I: core::slice::SliceIndex<[S]>, { diff --git a/core/src/traits/increment.rs b/core/src/traits/increment.rs new file mode 100644 index 0000000..c3e0579 --- /dev/null +++ b/core/src/traits/increment.rs @@ -0,0 +1,73 @@ +/* + Appellation: increment + Contrib: FL03 +*/ + +/// [Decrement] is a trait that provides a common interface for decrementing values; i.e., +/// subtracting one from a value. +pub trait Decrement { + fn decrement(self) -> Self; +} + +/// [DecrementAssign] is a trait that provides a common interface for decrementing values in +/// place. +pub trait DecrementAssign { + fn decrement_assign(&mut self); +} + +/// [Increment] is a trait that provides a common interface for incrementing values; i.e., +/// adding one to a value. +pub trait Increment { + fn increment(self) -> Self; +} + +/// [IncrementAssign] is a trait that provides a common interface for incrementing values in +/// place. +pub trait IncrementAssign { + fn increment_assign(&mut self); +} + +/// [Incremental] is a trait that provides a common interface for incrementing and decrementing values. +pub trait Incremental: Decrement + Increment + DecrementAssign + IncrementAssign {} + +/* + ************* Implementations ************* + */ + +impl Decrement for T +where + T: num::One + core::ops::Sub, +{ + fn decrement(self) -> Self { + self - T::one() + } +} + +impl DecrementAssign for T +where + T: num::One + core::ops::SubAssign, +{ + fn decrement_assign(&mut self) { + *self -= T::one(); + } +} + +impl Increment for T +where + T: num::One + core::ops::Add, +{ + fn increment(self) -> Self { + self + T::one() + } +} + +impl IncrementAssign for T +where + T: num::One + core::ops::AddAssign, +{ + fn increment_assign(&mut self) { + *self += T::one(); + } +} + +impl Incremental for T where T: Decrement + Increment + DecrementAssign + IncrementAssign {} diff --git a/core/src/traits/mod.rs b/core/src/traits/mod.rs index 2dbf4d9..b8a0271 100644 --- a/core/src/traits/mod.rs +++ b/core/src/traits/mod.rs @@ -3,11 +3,12 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{execute::*, symbolic::*, transform::*}; +pub use self::{execute::*, increment::*, symbolic::*, transform::*}; -pub mod execute; -pub mod symbolic; -pub mod transform; +pub(crate) mod execute; +pub(crate) mod increment; +pub(crate) mod symbolic; +pub(crate) mod transform; #[doc(hidden)] pub mod cspace; @@ -16,6 +17,7 @@ pub mod io; pub(crate) mod prelude { pub use super::execute::*; + pub use super::increment::*; pub use super::symbolic::*; pub use super::transform::*; } diff --git a/core/src/types/cursor.rs b/core/src/types/cursor.rs new file mode 100644 index 0000000..de47332 --- /dev/null +++ b/core/src/types/cursor.rs @@ -0,0 +1,193 @@ +/* + Appellation: cursor + Contrib: FL03 +*/ +use crate::Direction; + +/// Here, [Cursor] describes a type capable of tracking both the position and number of steps +/// taken by an actor. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Cursor { + /// The current position of the cursor. + pub(crate) position: Idx, + /// The number of steps taken by the cursor. + pub(crate) ticks: usize, +} + +impl Cursor { + pub fn new() -> Cursor + where + Idx: Default, + { + Cursor { + position: Idx::default(), + ticks: 0, + } + } + /// Resets the cursor to its initial state. + pub fn reset(&mut self) + where + Idx: Default, + { + self.position = Idx::default(); + self.ticks = 0; + } + /// Returns the current position of the cursor. + pub const fn position(&self) -> &Idx { + &self.position + } + + pub fn ticks(&self) -> usize { + self.ticks + } + + pub fn set_position(&mut self, position: Idx) { + self.position = position; + self.on_update() + } + /// Shifts the cursor in the given direction. + pub fn shift(&mut self, direction: Direction) + where + Idx: core::ops::AddAssign, + { + self.position += direction; + self.on_update() + } + + pub fn shift_left(&mut self) + where + Idx: core::ops::AddAssign, + { + self.shift(Direction::Left) + } + + pub fn shift_right(&mut self) + where + Idx: core::ops::AddAssign, + { + self.shift(Direction::Right) + } + + pub fn stay(&mut self) { + self.on_update() + } + + pub(crate) fn on_update(&mut self) { + self.ticks += 1; + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct Ticker { + pub(crate) ticks: T, +} + +impl Ticker { + pub fn new() -> Self + where + T: Default, + { + Self { + ticks: T::default(), + } + } + + pub const fn get(&self) -> &T { + &self.ticks + } + + pub fn reset(&mut self) + where + T: Default, + { + self.ticks = T::default(); + } + + pub fn set(&mut self, ticks: T) { + self.ticks = ticks; + } + + pub fn tick(&mut self) + where + T: core::ops::AddAssign + num::One, + { + self.ticks += T::one(); + } +} + +impl core::convert::AsRef for Ticker { + fn as_ref(&self) -> &T { + &self.ticks + } +} + +impl core::convert::AsMut for Ticker { + fn as_mut(&mut self) -> &mut T { + &mut self.ticks + } +} + +impl core::ops::Deref for Ticker { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.ticks + } +} + +impl core::ops::DerefMut for Ticker { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ticks + } +} + +impl core::iter::Iterator for Ticker +where + T: Copy + core::ops::AddAssign + num::One, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.tick(); + Some(self.ticks) + } +} + +impl core::cmp::PartialEq for Ticker +where + T: PartialEq, +{ + fn eq(&self, other: &T) -> bool { + &self.ticks == other + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_cursor() { + let mut cursor = Cursor::::new(); + assert_eq!(*cursor.position(), 0); + assert_eq!(cursor.ticks(), 0); + + cursor.shift(Direction::Right); + assert_eq!(*cursor.position(), 1); + assert_eq!(cursor.ticks(), 1); + + cursor.shift(Direction::Left); + assert_eq!(*cursor.position(), 0); + assert_eq!(cursor.ticks(), 2); + + cursor.shift(Direction::Stay); + assert_eq!(*cursor.position(), 0); + assert_eq!(cursor.ticks(), 3); + + cursor.set_position(10); + assert_eq!(*cursor.position(), 10); + assert_eq!(cursor.ticks(), 4); + } +} diff --git a/core/src/types/head.rs b/core/src/types/head.rs index 57c1a44..7c9be8c 100644 --- a/core/src/types/head.rs +++ b/core/src/types/head.rs @@ -8,7 +8,7 @@ use crate::state::State; /// With respect to a Turing machine, the head defines the current state and symbol of the /// machine. When associated with a direction the head becomes a tail, instructing the machine /// to move, write, and transition to a new state. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), @@ -17,7 +17,7 @@ use crate::state::State; pub struct Head { #[cfg_attr(feature = "serde", serde(alias = "current_state"))] pub state: State, - #[cfg_attr(feature = "serde", serde(flatten, alias = "current_symbol"))] + #[cfg_attr(feature = "serde", serde(alias = "current_symbol"))] pub symbol: S, } @@ -134,13 +134,13 @@ impl Head { impl Head { pub fn shift(self, direction: crate::Direction) -> Self { Self { - symbol: direction.apply(self.symbol), + symbol: direction.apply_unsigned(self.symbol), ..self } } pub fn shift_inplace(&mut self, direction: crate::Direction) { - self.symbol = direction.apply(self.symbol); + self.symbol = direction.apply_unsigned(self.symbol); } } @@ -192,6 +192,29 @@ impl<'a, Q, S> Head<&'a mut Q, &'a mut S> { } } +impl core::fmt::Debug for Head +where + Q: core::fmt::Debug, + S: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Head") + .field(&self.state) + .field(&self.symbol) + .finish() + } +} + +impl core::fmt::Display for Head +where + Q: core::fmt::Display, + S: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "({}, {})", self.state, self.symbol) + } +} + impl From<(Q, S)> for Head { fn from((state, symbol): (Q, S)) -> Self { Self::new(State(state), symbol) diff --git a/core/src/types/mod.rs b/core/src/types/mod.rs index f3fdefe..8ebfe12 100644 --- a/core/src/types/mod.rs +++ b/core/src/types/mod.rs @@ -3,16 +3,18 @@ Contrib: FL03 */ #[doc(inline)] -pub use self::{direction::Direction, head::Head, tail::Tail}; +pub use self::{head::Head, tail::Tail}; -pub mod direction; -pub mod head; -pub mod tail; +pub(crate) mod head; +pub(crate) mod tail; + +#[doc(hidden)] +pub mod cursor; pub(crate) mod prelude { - pub use super::direction::Direction; pub use super::head::Head; pub use super::tail::Tail; + pub use super::IndexedHead; #[allow(unused)] pub(crate) use super::Idx; @@ -20,5 +22,5 @@ pub(crate) mod prelude { /// A type alias generally used to represent the position of a value within a collection. pub(crate) type Idx = usize; -/// +/// A type alias for a head which store an index as its symbol pub type IndexedHead = Head; diff --git a/core/src/types/tail.rs b/core/src/types/tail.rs index 4f389e8..308712a 100644 --- a/core/src/types/tail.rs +++ b/core/src/types/tail.rs @@ -6,18 +6,21 @@ pub use self::builder::TailBuilder; use crate::{Direction, Head, State}; -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +/// The [Tail] is a 3-tuple containing the direction, state, and symbol that an actor is +/// instructed to execute whenever it assumes the head configuration assigned to the tail. +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(rename_all = "lowercase") +)] pub struct Tail { pub direction: Direction, - #[cfg_attr( - feature = "serde", - serde(flatten, alias = "state", alias = "next_state") - )] + #[cfg_attr(feature = "serde", serde(alias = "next_state"))] pub state: State, #[cfg_attr( feature = "serde", - serde(flatten, alias = "symbol", alias = "write_symbol") + serde(alias = "next_symbol", alias = "write_symbol") )] pub symbol: S, } @@ -161,6 +164,30 @@ impl<'a, Q, S> Tail<&'a mut Q, &'a mut S> { } } +impl core::fmt::Debug for Tail +where + Q: core::fmt::Debug, + S: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Tail") + .field(&self.direction) + .field(&self.state) + .field(&self.symbol) + .finish() + } +} + +impl core::fmt::Display for Tail +where + Q: core::fmt::Display, + S: core::fmt::Display, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}({}, {})", self.direction, self.state, self.symbol) + } +} + mod builder { use super::*; diff --git a/core/tests/actor.rs b/core/tests/actor.rs index a5e44c6..8742ef4 100644 --- a/core/tests/actor.rs +++ b/core/tests/actor.rs @@ -33,5 +33,8 @@ fn busy_beaver() { .build(); let actor = Actor::from_state(State(0)).with_tape(input); - assert!(actor.execute(program).run().is_ok()); + let mut rt = actor.execute(program); + for _ in 0..10 { + assert!(rt.next().is_some()); + } } diff --git a/rstm/examples/actor.rs b/rstm/examples/actor.rs index e6c738e..5e53b2e 100644 --- a/rstm/examples/actor.rs +++ b/rstm/examples/actor.rs @@ -9,9 +9,9 @@ use rstm::{ruleset, Actor, Program, State}; fn main() -> Result<(), Box> { _tracing(); // initialize the tape data - let alpha = vec![0_i8; 10]; + let alpha = vec![0u8; 10]; // initialize the state of the machine - let initial_state = State(0); + let initial_state = State(0isize); // define the ruleset for the machine let rules = ruleset![ (0, 0) -> Right(1, 0), @@ -43,8 +43,10 @@ fn _tracing() { tracing::info!("Welcome to rstm!"); } +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum S3 { - A, - B, - C, + A = 0, + B = 1, + C = -1, } diff --git a/rstm/examples/basic.rs b/rstm/examples/basic.rs index 568b97f..0872b87 100644 --- a/rstm/examples/basic.rs +++ b/rstm/examples/basic.rs @@ -4,7 +4,7 @@ */ extern crate rstm; -use rstm::{ruleset, Program, State, Tape, TM}; +use rstm::{ruleset, Program, State, StdTape, Turm}; fn main() -> Result<(), Box> { _tracing("debug"); @@ -23,9 +23,9 @@ fn main() -> Result<(), Box> { // create a new program with the rules let program = Program::new().initial_state(State(0)).rules(rules).build(); // create a new tape with the data - let tape = Tape::from_iter(alpha); + let tape = StdTape::from_iter(alpha); // create a new instance of the machine - let tm = TM::new(program, tape); + let tm = Turm::new(program, tape); tm.execute()?; Ok(()) } diff --git a/rstm/src/lib.rs b/rstm/src/lib.rs index ca3dd8e..04b9f08 100644 --- a/rstm/src/lib.rs +++ b/rstm/src/lib.rs @@ -20,7 +20,7 @@ extern crate alloc; pub use rstm_core::*; #[doc(inline)] -pub use self::turing::TM; +pub use self::turing::Turm; #[macro_use] pub(crate) mod macros {} @@ -28,6 +28,6 @@ pub(crate) mod macros {} pub mod turing; pub mod prelude { - pub use crate::turing::TM; + pub use crate::turing::Turm; pub use rstm_core::prelude::*; } diff --git a/rstm/src/turing.rs b/rstm/src/turing.rs index 4daa6f3..49deae4 100644 --- a/rstm/src/turing.rs +++ b/rstm/src/turing.rs @@ -2,38 +2,35 @@ Appellation: tm Contrib: FL03 */ -pub use self::{model::Turing, state::TMS}; -pub(crate) mod model; -pub(crate) mod state; -use crate::prelude::{Error, Head, Symbolic, Tail, Tape}; +use crate::prelude::{Error, HaltState, Head, StdTape, Symbolic, Tail}; use crate::rules::Program; use crate::state::State; -/// # Turing Machine ([TM]) +/// # Turing Machine ([Turm]) /// /// The Turing Machine is a mathematical model of computation that uses a set of rules to determine /// how a machine should manipulate a tape. The machine can read, write, and move linearly across the tape. /// Each pre-defined rule maps a head, consisting of a state and symbol, to a new state and symbol along with a direction. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct TM { +pub struct Turm { pub(crate) program: Program, - pub(crate) state: State, - pub(crate) tape: Tape, + pub(crate) state: HaltState, + pub(crate) tape: StdTape, } -impl TM { - pub fn new(program: Program, tape: Tape) -> Self +impl Turm { + pub fn new(program: Program, tape: StdTape) -> Self where Q: Clone + Default, S: Default, { let state = program.initial_state().cloned(); - TM { + Turm { program, - state, + state: HaltState::state(state), tape, } } @@ -51,19 +48,19 @@ impl TM { /// Returns an instance of the [state](State) with an immutable /// reference to the internal data pub fn state(&self) -> State<&'_ Q> { - self.state.to_ref() + self.state.as_state() } /// Returns an instance of the [state](State) with a mutable /// reference to the internal data pub fn state_mut(&mut self) -> State<&'_ mut Q> { - self.state.to_mut() + self.state.as_mut_state() } /// Returns an immutable reference to the [tape](StdTape) - pub const fn tape(&self) -> &Tape { + pub const fn tape(&self) -> &StdTape { &self.tape } /// Returns a mutable reference to the [tape](StdTape) - pub fn tape_mut(&mut self) -> &mut Tape { + pub fn tape_mut(&mut self) -> &mut StdTape { &mut self.tape } /// Runs the program until the @@ -116,16 +113,17 @@ impl TM { symbol, }) = self.program.get_ref(self.read()?) { + // self.tape.update(direction, symbol.clone()); - self.state = state.cloned(); + self.state = state.cloned().into(); return Some(Head::new(state, symbol)); } unreachable!("No instruction found for the current head") } } -impl core::iter::Iterator for TM +impl core::iter::Iterator for Turm where Q: Clone + PartialEq + 'static, S: Clone + PartialEq, diff --git a/rstm/src/turing/model.rs b/rstm/src/turing/model.rs deleted file mode 100644 index 7b62e86..0000000 --- a/rstm/src/turing/model.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* - Appellation: model - Contrib: FL03 -*/ -use crate::Alphabet; - -#[doc(hidden)] -pub trait Turing { - type Alpha: Alphabet; // input alphabet - type Beta: Alphabet; // output alphabet - - fn step(&mut self, input: Self::Alpha) -> Self::Beta; -} diff --git a/rstm/src/turing/state.rs b/rstm/src/turing/state.rs deleted file mode 100644 index 0cc7932..0000000 --- a/rstm/src/turing/state.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Appellation: turing - Contrib: FL03 -*/ -use crate::state::{Halt, State}; - -/// [TMS] extends the T -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - strum::AsRefStr, - strum::EnumCount, - strum::EnumIs, -)] -pub enum TMS { - Halt(State>), - State(State), -} - -impl TMS { - pub fn halt(State(state): State>) -> Self { - TMS::Halt(State(state)) - } - - pub fn state(state: State) -> Self { - TMS::State(state) - } - - pub fn into_halt(self) -> State> { - match self { - TMS::Halt(state) => state, - TMS::State(state) => state.halt(), - } - } - - pub fn into_state(self) -> State { - match self { - TMS::Halt(state) => state.unhalt(), - TMS::State(state) => state, - } - } -}