Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V0.0.3 #8

Merged
merged 36 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/crates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
workflow_dispatch:

jobs:
independents:
base:
env:
CRATE_NAME: ${{ github.event.repository.name }}-${{ matrix.suffix }}
name: Publish (${{ matrix.suffix }})
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ thiserror = "1"

[workspace.package]
authors = ["Joe McCain III <jo3mccain@icloud.com>",]
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"
version = "0.0.2"
version = "0.0.3"

[profile.dev]
opt-level = 0
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,27 @@ cargo build --features full -r --workspace
```rust
extern crate rstm;

fn main() -> Result<(), Box<dyn std::error::Error>> {
use rstm::state::BinState::{Invalid, Valid};
use rstm::{rule, Program, State, StdTape, TM};

fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt().with_target(false).init();

// initialize the tape data
let alpha: Vec<u8> = 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 = StdTape::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(())
}
```
Expand Down
305 changes: 305 additions & 0 deletions core/src/actors/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
/*
Appellation: actor <module>
Contrib: FL03 <jo3mccain@icloud.com>
*/
#[doc(inline)]
pub use self::builder::ActorBuilder;

use super::Executor;
use crate::rules::Program;
use crate::{Direction, Error, 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<Q, S> {
/// the input alphabet
pub(crate) alpha: Vec<S>,
/// the head of the tape
pub(crate) head: Head<Q, usize>,
/// the number of steps taken by the actor
pub(crate) steps: usize,
}

impl<Q, S> Actor<Q, S> {
Fixed Show fixed Hide fixed
///
Fixed Show fixed Hide fixed
pub fn new() -> ActorBuilder<Q, S> {
ActorBuilder::new()
}
Fixed Show fixed Hide fixed
Comment on lines +24 to +26

Check warning

Code scanning / clippy

methods called new usually return Self Warning

methods called new usually return Self
/// 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<Q>) -> Self {
Self {
alpha: Vec::new(),
head: Head {
state: State(state),
symbol: 0,
},
steps: 0,
}
}

pub fn with_tape<I>(self, alpha: I) -> Self
where
I: IntoIterator<Item = S>,
{
Self {
alpha: Vec::from_iter(alpha),
..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<Q, usize> {
&self.head
}
/// Returns a mutable reference to the head of the tape
pub fn head_mut(&mut self) -> &mut Head<Q, usize> {
&mut self.head
}
/// Returns an instance of the state with an immutable reference to the inner value
pub fn state(&self) -> State<&Q> {
self.head.state()
}
/// 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<Q, S>) -> Executor<Q, S> {
Executor::new(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.head.state.is_halt()
}
/// Returns the length of the tape
#[inline]
pub fn len(&self) -> usize {
Fixed Show fixed Hide fixed
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",
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<Head<&Q, &S>> {
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) -> Result<Head<&Q, &S>, Error> {
#[cfg(feature = "tracing")]
tracing::trace!("Reading the tape...");
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
#[cfg_attr(
feature = "tracing",
tracing::instrument(skip_all, name = "write", target = "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() {
#[cfg(feature = "tracing")]
tracing::trace!("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 = "handle", target = "actor")
)]
pub(crate) fn handle(&mut self, direction: Direction, State(next_state): State<Q>, 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")
)]
pub(crate) fn step(
&mut self,
direction: Direction,
State(state): State<Q>,
symbol: S,
) -> Result<Head<&Q, &S>, 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;
}
}

impl<Q, S> core::fmt::Debug for Actor<Q, S>
where
S: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
for (i, c) in self.alpha.iter().enumerate() {
if i == self.position() {
write!(f, "[{c:?}]")?;
} else {
write!(f, "{c:?}")?;
}
}
Ok(())
}
}

impl<Q, S> core::fmt::Display for Actor<Q, S>
where
S: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
for (i, c) in self.alpha.iter().enumerate() {
if i == self.position() {
write!(f, "[{c}]")?;
} else {
write!(f, "{c}")?;
}
}
Ok(())
}
}

mod builder {
use super::*;
use core::iter::FromIterator;

#[derive(Default)]
pub struct ActorBuilder<Q, S> {
alpha: Vec<S>,
state: Option<State<Q>>,
symbol: usize,
}

impl<Q, S> ActorBuilder<Q, S> {
pub(crate) fn new() -> Self {
Self {
alpha: Vec::new(),
state: None,
symbol: 0,
}
}

pub fn alpha<I>(self, alpha: I) -> Self
where
I: IntoIterator<Item = S>,
{
Self {
alpha: Vec::from_iter(alpha),
..self
}
}

pub fn head(self, head: Head<Q, usize>) -> Self {
Self {
state: Some(head.state),
symbol: head.symbol,
..self
}
}

pub fn state(self, State(state): State<Q>) -> Self {
Self {
state: Some(State(state)),
..self
}
}

pub fn position(self, symbol: usize) -> Self {
Self { symbol, ..self }
}

pub fn build(self) -> Actor<Q, S>
where
Q: Default,
{
let ActorBuilder {
alpha,
state,
symbol,
} = self;
Actor {
alpha,
head: Head {
state: state.unwrap_or_default(),
symbol,
},
steps: 0,
}
}
}
}
Loading
Loading