With these minor modifications in place, we can represent DFAs with python tuples and sets super easily. Here are two examples, which we will use. One important thing to notice is that the set of states and of symbols can accommodate many different types - they are not limited to just being strings!
run(·) that takes a sequence of symbols from
the machine's alphabet and runs the machine on that input,
returning True if the input is accepted
and False otherwise. Along with the code are a few
sample runs.
$ python3 -i dfa.py >>> from ex0 import M0 >>> M = DFA(M0) >>> M.run("abaabc") True >>> from ex1 import M1 >>> Mp = DFA(M1) >>> Mp.run([6,4,6,8]) True |
>>> a,b,c = (2*5+1,"foobar",{'a','b'}) >>> a 11 >>> b 'foobar' >>> c {'b', 'a'}
Tmap is, and how the heck it works!
run work
in he example below, even though one uses a string and the
other a list?
>>> from ex0 import M0 >>> M = DFA(M0) >>> M.run("abaabc") True >>> M.run(['a','b','a','a','b','c']) True
KeyError exception? Find an input to
give run
that causes the KeyError exception. (You might want to add
a temporary print or something to make sure that you really
are causing a KeyError exception.)
run, except that it prints out
a representation of the computation in the form shown below.
Important! To tell print not to
stick a newline at the end, call it like: print("blah",end="")
>>> from ex0 import M0 >>> M = DFA(M0) >>> M.showrun("abaabc") q1 =a=> q2 =b=> q2 =a=> q1 =a=> q2 =b=> q2 =c=> q3 True >>> M.showrun("ac") q1 =a=> q2 =c=> q3 True |
>>> from ex1 import M1 >>> Mp = DFA(M1) >>> Mp.showrun([6,4,6,8]) 1 =6=> 1 =4=> 2 =6=> 2 =8=> 3 True |
plv2, which takes an
input just like run, but which returns three values
(literally just return three comma-separated values) that are
strings x, y and z from the pumping lemma version 2.0.
You may assume the input is accepted by the machine.
>>> from ex0 import M0 >>> M = DFA(M0) >>> M.showrun("abaabc") q1 =a=> q2 =b=> q2 =a=> q1 =a=> q2 =b=> q2 =c=> q3 True >>> x,y,z = M.plv2("abaabc") >>> f"x = {x}, y = {y}, z = {z}" 'x = a, y = b, z = aabc'Here's another example input. The line:
>>> Mx = ({0,1,2},{'b','a'},{(1,'b',0),(1,'a',2),(2,'a',0),(2,'b',1),(0,'a',1),(0,'b',2)},0,{0})
... defines the machine:
>>> M0 = DFA(Mx) >>> M0.showrun("bbaaab") 0 =b=> 2 =b=> 1 =a=> 2 =a=> 0 =a=> 1 =b=> 0 True >>> M0.plv2("bbaaab") ('b', 'ba', 'aab') >>> M0.showrun("babaab") 0 =b=> 2 =a=> 0 =b=> 2 =a=> 0 =a=> 1 =b=> 0 True >>> M0.plv2("babaab") ('', 'ba', 'baab')
Important!
M that mapped a state
to the counter value from when I first encountered that
state. When I moved to state q, I checked whether q was
already a key in the map (q in M). If so, I
found a loop in the computation, and I could use the
counter values to figure out the substring ranges for x, y
and z.
w is a string, and i and j are integer
indices, w[i:j] is the substring
$w_iw_{i+1}\cdots w_{j-1}$. Also,
w[:j] is short for "w[0:j]", and
w[i:] is short for "w[i:n]",
where $n$ is the length of $w$. These are called
"slices". They work exactly the same way for lists!
>>> s = "beatarmy" >>> s[1:4] 'eat' >>> s[:4] 'beat' >>> s[4:] 'army'