Last active
January 2, 2016 23:29
-
-
Save vermiculus/8376562 to your computer and use it in GitHub Desktop.
A state machine implementing on/off functionality with a momentary-latch push-button.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import print_function | |
class DeterministicFiniteAutomaton: | |
"""A simple DFA-ish class for Python. | |
Note that this does not implement accept states. | |
>>> dfa = DeterministicFiniteAutomaton('off', { | |
... ('on', 0): ('on', None), | |
... ('on', 1): ('on-off', None), | |
... ('on-off', 1): ('on-off', None), | |
... ('on-off', 0): ('off', lambda: print('turning off')), | |
... ('off', 0): ('off', None), | |
... ('off', 1): ('off-on', None), | |
... ('off-on', 1): ('off-on', None), | |
... ('off-on', 0): ('on', lambda: print('turning on')) | |
... }) | |
>>> dfa.state | |
'off' | |
>>> dfa.read(1) | |
>>> dfa.state | |
'off-on' | |
>>> dfa.read(1) | |
>>> dfa.state | |
'off-on' | |
>>> dfa.read(0) | |
turning on | |
>>> dfa.state | |
'on' | |
>>> dfa.read('banana') | |
Traceback (most recent call last): | |
... | |
Exception: No transition from 'on' for letter 'banana' | |
""" | |
def __init__(self, initial_state, transition_table): | |
"""Creates a DFA""" | |
if initial_state not in map(lambda k: k[0], transition_table.keys()): | |
raise KeyError("Are you sure you don't have transitions from your initial state?") | |
self.state_old = None | |
self.state = initial_state | |
self.transitions = transition_table | |
def read(self, letter): | |
"""Read a letter and update the state, calling any appropriate | |
functions when the state has been updated.""" | |
# See if we have a transition defined for this state on this | |
# letter; even if that transition is to itself. | |
if letter not in map(lambda k: k[1], | |
filter(lambda j: j[0] == self.state, | |
self.transitions.keys())): | |
raise Exception('No transition from {!r} for letter {!r}'.format(self.state, letter)) | |
# Temporarily store the new state for ease of access | |
newstate = self.transitions[(self.state, letter)] | |
# Update state | |
self.oldstate = self.state | |
self.state = newstate[0] | |
# If we just moved to this state, call the edge function. | |
if self.oldstate != self.state and callable(newstate[1]): | |
newstate[1]() | |
# TODO: Edges from a state to itself are still edges and they | |
# should be callable. However, this is not important for any use | |
# case I can think of, since you generally don't want to *always* | |
# be doing something---only when you encounter a change. | |
def read_list(self, letters): | |
"""Read each letter in `letters' in order""" | |
map(self.read, letters) | |
import pprint | |
testdfa = DeterministicFiniteAutomaton('off', { | |
('on', 0): ('on', None), | |
('on', 1): ('on-off', None), | |
('on-off', 1): ('on-off', None), | |
('on-off', 0): ('off', lambda: pprint.pprint('off')), | |
('off', 0): ('off', None), | |
('off', 1): ('off-on', None), | |
('off-on', 1): ('off-on', None), | |
('off-on', 0): ('on', lambda: pprint.pprint('on')) | |
}) | |
if __name__ == '__main__': | |
import doctest | |
doctest.testmod() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\documentclass[tikz]{standalone} | |
\usetikzlibrary{automata} | |
\begin{document} | |
\begin{tikzpicture}[shorten >=1pt,node distance=3cm,auto,thick] | |
\node [state, initial] (off) {Off}; | |
\node [state] (on-off) [above right of=off] {}; | |
\node [state] (off-on) [below right of=off] {}; | |
\node [state] (on) [below right of=on-off] {On}; | |
\path[->] | |
(off) edge [loop above] node {0} (off) | |
edge node {1} (off-on) | |
(off-on) edge [loop above] node {1} (off-on) | |
edge node {0} (on) | |
(on) edge [loop above] node {0} (on) | |
edge node {1} (on-off) | |
(on-off) edge [loop above] node {1} (on-off) | |
edge node {0} (off); | |
\end{tikzpicture} | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment