Skip to content

Commit

Permalink
Release v0.4.2
Browse files Browse the repository at this point in the history
  • Loading branch information
kelvindecosta committed Jun 25, 2020
1 parent 2c2f3c6 commit c01e0c7
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 40 deletions.
19 changes: 6 additions & 13 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name="alan",
version="0.4.1",
version="0.4.2",
description="A programming language for designing Turing machines",
long_description=long_description,
long_description_content_type="text/markdown",
Expand All @@ -19,16 +19,9 @@
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
packages=find_packages("src"),
package_dir={"" : "src"},
install_requires=[
"imageio",
"pydot"
],
entry_points={
"console_scripts": [
"alan = alan.__main__:main",
]
},
python_requires=">=3.6",
packages=["alan"],
package_dir={"alan": "src"},
install_requires=["imageio", "pydot"],
entry_points={"console_scripts": ["alan = alan.__main__:main",]},
)
File renamed without changes.
1 change: 1 addition & 0 deletions src/alan/__main__.py → src/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ def main():
else:
print(result)


if __name__ == "__main__":
main()
12 changes: 10 additions & 2 deletions src/alan/interface.py → src/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@
def parse_args():
"""Parses arguments
"""
parser = ArgumentParser(description="A programming langauge for designing Turing Machines", prog="alan")
parser = ArgumentParser(
description="A programming langauge for designing Turing Machines", prog="alan"
)
commands = parser.add_subparsers(dest="command")

# p_run
p_run = commands.add_parser("run", help="run machine on tape")
p_run.add_argument("definition", type=str, help="path to definition file")
p_run.add_argument("tape", type=str, help="string of tape symbols")
p_run.add_argument("-s", "--max-steps", type=int, help="maximum steps before forcing halt", default=200)
p_run.add_argument(
"-s",
"--max-steps",
type=int,
help="maximum steps before forcing halt",
default=200,
)
p_run.add_argument("-a", "--animate", action="store_true")
p_run.add_argument("-f", "--filename", type=str, help="path to save animation")
p_run.add_argument("-r", "--fps", type=int, help="animation fps", default=1)
Expand Down
81 changes: 56 additions & 25 deletions src/alan/machine.py → src/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re
from pydot import Dot, Edge, Node, Subgraph


class Machine:
"""
The abstract class for a Turing Machine.
Expand All @@ -22,7 +23,6 @@ def __init__(self):
self._tape = None
self._head = None


def _set_symbol(self, symbol, blank=False):
"""
Adds a symbol to the set of symbols of the Machine.
Expand All @@ -41,8 +41,9 @@ def _set_symbol(self, symbol, blank=False):
if blank:
self._blank_symbol = symbol
except:
raise Exception(f"Machine got blank symbol '{symbol}' which is already set to '{self._blank_symbol}'")

raise Exception(
f"Machine got blank symbol '{symbol}' which is already set to '{self._blank_symbol}'"
)

def _set_state(self, state, start=False, end=False):
"""
Expand All @@ -65,10 +66,13 @@ def _set_state(self, state, start=False, end=False):
if start:
self._start_state = state
except:
raise Exception(f"Machine got start state '{state}' which is already set to '{self._start_state}'")
raise Exception(
f"Machine got start state '{state}' which is already set to '{self._start_state}'"
)


def _set_transition(self, current_state, current_symbol, next_symbol, direction, next_state):
def _set_transition(
self, current_state, current_symbol, next_symbol, direction, next_state
):
"""
Adds a transition to the set of transitions of the Machine.
Expand All @@ -87,8 +91,11 @@ def _set_transition(self, current_state, current_symbol, next_symbol, direction,
if self._transitions.get(current_state) is None:
self._transitions[current_state] = {}

self._transitions[current_state][current_symbol] = (next_symbol, direction, next_state)

self._transitions[current_state][current_symbol] = (
next_symbol,
direction,
next_state,
)

def parse(self, definition):
"""
Expand All @@ -99,9 +106,16 @@ def parse(self, definition):
"""
comment_re = re.compile(r"(#.*)")
state_re = re.compile(r"^([a-zA-Z_][a-zA-Z0-9_]*)([.*])?$")
transition_re = re.compile(r"^'(.)'\s+'(.)'\s+([<>])\s+([a-zA-Z_][a-zA-Z0-9_]*)$")

lines = list(filter(lambda x : len(x) > 0, map(lambda x: comment_re.sub("", x).strip(), definition.split("\n"))))
transition_re = re.compile(
r"^'(.)'\s+'(.)'\s+([<>])\s+([a-zA-Z_][a-zA-Z0-9_]*)$"
)

lines = list(
filter(
lambda x: len(x) > 0,
map(lambda x: comment_re.sub("", x).strip(), definition.split("\n")),
)
)
self._set_symbol(lines.pop(0)[1], True)

scope_state = None
Expand All @@ -120,7 +134,6 @@ def parse(self, definition):
except:
pass


def reset(self, tape):
"""
Resets the tape, head and state of the Machine.
Expand All @@ -132,7 +145,6 @@ def reset(self, tape):
self._tape = list(tape)
self._head = 0


def step(self):
"""
Performs one Machine step.
Expand All @@ -142,7 +154,9 @@ def step(self):
"""
try:
current_symbol = self._tape[self._head]
next_symbol, direction, self._current_state = self._transitions.get(self._current_state).get(current_symbol)
next_symbol, direction, self._current_state = self._transitions.get(
self._current_state
).get(current_symbol)
except:
return True

Expand All @@ -158,7 +172,6 @@ def step(self):

return False


def run(self, tape, max_steps=200, animate=False, **kwargs):
"""
Performs a computation by the Machine on a tape
Expand All @@ -183,11 +196,14 @@ def run(self, tape, max_steps=200, animate=False, **kwargs):
raise Exception("Specify a filename to save the animation")
images = []


for _ in range(max_steps):
if animate:
images.append(imageio.imread(self.graph(False).create(prog="dot", format="png")))
images.append(imageio.imread(self.graph(True).create(prog="dot", format="png")))
images.append(
imageio.imread(self.graph(False).create(prog="dot", format="png"))
)
images.append(
imageio.imread(self.graph(True).create(prog="dot", format="png"))
)

halt = self.step()
if halt:
Expand All @@ -196,8 +212,11 @@ def run(self, tape, max_steps=200, animate=False, **kwargs):
if animate:
imageio.mimsave(kwargs.get("filename"), images, fps=kwargs.get("fps"))

return halt, halt and self._current_state in self._end_states, "".join(self._tape).strip(self._blank_symbol)

return (
halt,
halt and self._current_state in self._end_states,
"".join(self._tape).strip(self._blank_symbol),
)

def graph(self, context=None, **kwargs):
"""
Expand All @@ -210,7 +229,9 @@ def graph(self, context=None, **kwargs):
[pydot.Dot] -- graph object
"""
graph = Dot(graph_type="digraph", rankdir=("LR" if context is None else "TB"))
machine_graph = Subgraph(graph_name="cluster_machine", graph_type="digraph", label="MACHINE")
machine_graph = Subgraph(
graph_name="cluster_machine", graph_type="digraph", label="MACHINE"
)

for current_state in sorted(self._states):
node_args = {}
Expand All @@ -235,16 +256,26 @@ def graph(self, context=None, **kwargs):
label = f"'{current_symbol}' '{next_symbol}' {'R' if direction else 'L'}"

edge_args = {}
if context and current_state == self._current_state and current_symbol == self._tape[self._head]:
if (
context
and current_state == self._current_state
and current_symbol == self._tape[self._head]
):
edge_args["color"] = "cyan"
machine_graph.add_edge(Edge(current_state, next_state, label=label, **edge_args))
machine_graph.add_edge(
Edge(current_state, next_state, label=label, **edge_args)
)

graph.add_subgraph(machine_graph)
if context is not None:
tape_graph = Subgraph(graph_name="cluster_tape", graph_type="digraph", label="TAPE")
tape_graph = Subgraph(
graph_name="cluster_tape", graph_type="digraph", label="TAPE"
)
tape = []
for index in range(-4 + self._head, 5 + self._head):
tape.append(f"<t{index}> {self._tape[index] if 0 <= index < len(self._tape) else self._blank_symbol}")
tape.append(
f"<t{index}> {self._tape[index] if 0 <= index < len(self._tape) else self._blank_symbol}"
)

tape_graph.add_node(Node("tape", label="|".join(tape), shape="record"))
tape_graph.add_node(Node("t0", shape="point"))
Expand Down

0 comments on commit c01e0c7

Please sign in to comment.