diff --git a/setup.py b/setup.py index 613b01a..0ac3e62 100644 --- a/setup.py +++ b/setup.py @@ -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", @@ -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",]}, ) diff --git a/src/alan/__init__.py b/src/__init__.py similarity index 100% rename from src/alan/__init__.py rename to src/__init__.py diff --git a/src/alan/__main__.py b/src/__main__.py similarity index 99% rename from src/alan/__main__.py rename to src/__main__.py index 89b5085..ed5c5d9 100644 --- a/src/alan/__main__.py +++ b/src/__main__.py @@ -24,5 +24,6 @@ def main(): else: print(result) + if __name__ == "__main__": main() diff --git a/src/alan/interface.py b/src/interface.py similarity index 77% rename from src/alan/interface.py rename to src/interface.py index 0204f06..09f6bf2 100644 --- a/src/alan/interface.py +++ b/src/interface.py @@ -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) diff --git a/src/alan/machine.py b/src/machine.py similarity index 77% rename from src/alan/machine.py rename to src/machine.py index 6691956..d28b27d 100644 --- a/src/alan/machine.py +++ b/src/machine.py @@ -2,6 +2,7 @@ import re from pydot import Dot, Edge, Node, Subgraph + class Machine: """ The abstract class for a Turing Machine. @@ -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. @@ -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): """ @@ -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. @@ -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): """ @@ -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 @@ -120,7 +134,6 @@ def parse(self, definition): except: pass - def reset(self, tape): """ Resets the tape, head and state of the Machine. @@ -132,7 +145,6 @@ def reset(self, tape): self._tape = list(tape) self._head = 0 - def step(self): """ Performs one Machine step. @@ -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 @@ -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 @@ -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: @@ -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): """ @@ -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 = {} @@ -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" {self._tape[index] if 0 <= index < len(self._tape) else self._blank_symbol}") + tape.append( + f" {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"))