Skip to content

Commit

Permalink
No commit message
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbadr committed Jun 8, 2007
1 parent 761d1f0 commit 5561b53
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
81 changes: 75 additions & 6 deletions DFA.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
# python-automata, the Python DFA library
# By Andrew Badr
# Version June 7, 2007
# Contact andrewbadr@gmail.com
# Your contributions are welcome.

#Copyright terms:
#You may redistribute it and/or modify python-automata under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation.

class DFA:
def __init__(self, states, start, delta, accepts, alphabet):
def __init__(self, states, alphabet, delta, start, accepts):
self.states = states
self.start = start
self.delta = delta
self.accepts = accepts
self.alphabet = alphabet
self.current_state = start
def pretty_print(self):
print "--------------------------"
print "States:", self.states
print "Alphabet:", self.alphabet
print "Starting state:", self.start
print "Accepting states:", self.accepts
print "Transition function:"
print "\t","\t".join(map(str,self.states))
for c in self.alphabet:
results = map(lambda x: self.delta(x, c), self.states)
print c, "\t", "\t".join(map(str, results))
print "Current state:", self.current_state
print "Currently accepting:", self.status()
def validate(self):
"""Checks that:
(1) The accepting-state set is a subset of the state set.
Expand Down Expand Up @@ -53,9 +75,39 @@ def state_merge(self, q1, q2):
next = q2
transitions[state][char] = next
self.delta = (lambda s, c: transitions[s][c])
def reachable_from(self, q0):
reached = [q0]
to_process = [q0]
while len(to_process):
q = to_process.pop()
for c in self.alphabet:
next = self.delta(q, c)
if next not in reached:
reached.append(next)
to_process.append(next)
return reached
def reachable(self):
return self.reachable_from(self.start)
def minimize(self):
"""Classical DFA minimization, using the simple O(n^2) algorithm"""
"""Side effect: can mix up the order of states"""
#print "starts with %d states" % len(self.states)
#print self.states

#Step 1: Delete unreachable states
reachable = self.reachable()
#print "but only these are reachable:", reachable
self.states = reachable
#print "New self.states:", self.states
#print "Old acceptance list:", self.accepts
new_accepts = []
for q in self.accepts:
if q in self.states:
new_accepts.append(q)
self.accepts = new_accepts
#print "New acceptance list:", self.accepts


changed = True
classes = [self.accepts, [x for x in set(self.states).difference(set(self.accepts))]]
while changed:
Expand Down Expand Up @@ -97,6 +149,7 @@ def minimize(self):
state_map = {}
#build new_states, new_start, new_current_state:
for state_class in classes:
#print "Processing state class:", state_class
representative = state_class[0]
new_states.append(representative)
for state in state_class:
Expand All @@ -114,6 +167,8 @@ def minimize(self):
for state in new_states:
transitions[state] = {}
for alpha in self.alphabet:
#print "transitions[%s][%s] = state_map[self.delta(%s, %s)]" % (state, alpha, state, alpha)
#print "transitions[%s][%s] = state_map[%s]" % (state, alpha, self.delta(state, alpha))
transitions[state][alpha] = state_map[self.delta(state, alpha)]
#print transitions
new_delta = (lambda s, a: transitions[s][a])
Expand Down Expand Up @@ -151,7 +206,8 @@ def find_fin_inf_parts(self):
finite_part.append(state)
return (finite_part, infinite_part)
def is_finite(self):
"""Indicates whether the DFA's language is a finite set. Could be improved to O(n)."""
"""Indicates whether the DFA's language is a finite set. Could be improved to O(n).
Minimizes the DFA as a side-effect."""
self.minimize()
(fin_part, inf_part) = self.find_fin_inf_parts()
if len(inf_part) != 1:
Expand Down Expand Up @@ -210,10 +266,23 @@ def finite_difference_minimize(self):
for fp_state in fins[1:]:
self.state_merge(fp_state, rep)
#print "After f-minimization, there are %s states" % len(self.states)
def DFCA_minimize(self, k):
"""Placeholder for DFCA minimization.
See "Minimal cover-automata for finite languages" for context.
def DFCA_minimize(self, l):
"""DFCA minimization.
Input: (self) is a DFA accepting a finite language, and (l) is the length of the longest word in its language
Result: (self) is DFCA-minimized
See "Minimal cover-automata for finite languages" for context on DFCAs, and
"An O(n^2) Algorithm for Constructing Minimal Cover Automata for Finite Languages"
for the source of this algorithm. (Campeanu, Paun, Santean, and Yu)
There exists a faster, O(n*logn)-time algorithm due to Korner, from CIAA 2002.
"""
assert(self.is_finite())
###Step 0: Numbering the states
###Step 1: Computing the gap function


###Step 2: Merging states
pass

def cross_product(D1, D2, accept_method):
Expand Down Expand Up @@ -242,7 +311,7 @@ def delta(state_pair, char):

def intersection(D1, D2):
"""Constructs an unminimized DFA recognizing the intersection of the languages of two given DFAs."""
f = lambda x,y: x and y
f = bool.__and__
return cross_product(D1, D2, f)

def union(D1, D2):
Expand Down
11 changes: 9 additions & 2 deletions demo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import DFA

#Basics:
states = range(5)
start = 0
accepts = [0]
Expand All @@ -20,6 +22,7 @@ def delta(state, char):
print d.current_state
print d.status()

#Finite difference minimization
states = range(5)
start = 0
accepts = [0, 2, 4]
Expand All @@ -29,5 +32,9 @@ def delta(state, char):
return state+1
else:
return 4
e = DFA.DFA(states, start, delta, accepts, alphabet)

e = DFA.DFA(states=states, start=start, delta=delta, accepts=accepts, alphabet=alphabet)
print "===The starting DFA==="
e.pretty_print()
print "===F-minimized==="
e.finite_difference_minimize()
e.pretty_print()

0 comments on commit 5561b53

Please sign in to comment.