Skip to content

Commit

Permalink
merging release-0.1.2 branch
Browse files Browse the repository at this point in the history
  • Loading branch information
marcofavorito committed Mar 16, 2018
2 parents be36339 + 6dd7367 commit b42e5e3
Show file tree
Hide file tree
Showing 35 changed files with 1,645 additions and 1,523 deletions.
7 changes: 6 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ History
0.1.1 (2018-03-15)
------------------

* basic DFA and NFA support;
* Basic DFA and NFA support;
* Algorithms for DFA minimization and trimming;
* Algorithm for NFA determinization.

0.1.2 (2018-03-16)
------------------

* Minor bug fixes
7 changes: 6 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Pythomata
.. image:: https://img.shields.io/pypi/pyversions/pythomata.svg
:target: https://pypi.python.org/pypi/pythomata

.. image:: https://img.shields.io/badge/status-development-orange.svg
:target: https://img.shields.io/badge/status-development-orange.svg

.. image:: https://img.shields.io/travis/MarcoFavorito/pythomata.svg
:target: https://travis-ci.org/MarcoFavorito/pythomata

Expand Down Expand Up @@ -40,7 +43,9 @@ Install
Features
--------

* TODO
* Basic DFA and NFA support;
* Algorithms for DFA minimization and trimming;
* Algorithm for NFA determinization.

Credits
-------
Expand Down
2 changes: 1 addition & 1 deletion pythomata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

__author__ = """Marco Favorito"""
__email__ = 'marco.favorito@gmail.com'
__version__ = '0.1.dev2'
__version__ = '0.1b2'
6 changes: 6 additions & 0 deletions pythomata/base/Alphabet.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ def __init__(self, symbols: Set[Symbol]):
@staticmethod
def fromStrings(symbol_strings:Set[str]):
return Alphabet(set(Symbol(s) for s in symbol_strings))

def __eq__(self, other):
if type(self)==type(other):
return self.symbols == other.symbols
else:
return False
66 changes: 33 additions & 33 deletions pythomata/base/DFA.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ def _check_input(self, alphabet, states, initial_state, accepting_states, transi
if s not in states or any(sym not in alphabet.symbols and next_state not in states for sym, next_state in sym2state.items()):
raise ValueError

@classmethod
def complete(cls, dfa):
def complete(self):
sink = Sink()
transitions = deepcopy(dfa.transition_function)
for state, sym2state in dfa.transition_function.items():
for action in dfa.alphabet.symbols:
transitions = deepcopy(self.transition_function)
for state, sym2state in self.transition_function.items():
for action in self.alphabet.symbols:
if not action in sym2state:
transitions[state][action]= sink
return DFA(dfa.alphabet, dfa.states.union({sink}), dfa.initial_state, dfa.accepting_states,
return DFA(self.alphabet, self.states.union({sink}), self.initial_state, self.accepting_states,
dict(transitions))

@classmethod
def minimize(cls, orig_dfa):
dfa = DFA.complete(orig_dfa)
def minimize(self):
dfa = self.complete()

# Greatest−fixpoint
z_current = set()
Expand Down Expand Up @@ -96,79 +94,81 @@ def minimize(cls, orig_dfa):

return DFA(dfa.alphabet, frozenset(equiv_class2new_state.values()), equiv_class2new_state[state2equiv_class[dfa.initial_state]], new_final_states, new_transition_function)

@classmethod
def reachable(cls, dfa):
def reachable(self):

# least fixpoint
z_current, z_next = set(), set()
z_next.add(dfa.initial_state)
z_next.add(self.initial_state)

while z_current != z_next:
z_current = z_next
z_next = deepcopy(z_current)
for s in z_current:
for a in dfa.transition_function.get(s, []):
next_state = dfa.transition_function[s][a]
for a in self.transition_function.get(s, []):
next_state = self.transition_function[s][a]
z_next.add(next_state)

new_states = z_current
new_transition_function = {}
for s in new_states:
for a in dfa.transition_function.get(s, []):
next_state = dfa.transition_function[s][a]
for a in self.transition_function.get(s, []):
next_state = self.transition_function[s][a]
if next_state in new_states:
new_transition_function.setdefault(s, {})
new_transition_function[s].setdefault(a, {})
new_transition_function[s][a] = next_state

new_final_states = frozenset(new_states.intersection(dfa.accepting_states))
new_final_states = frozenset(new_states.intersection(self.accepting_states))

return DFA(dfa.alphabet, new_states, dfa.initial_state, new_final_states, new_transition_function)
return DFA(self.alphabet, new_states, self.initial_state, new_final_states, new_transition_function)

@classmethod
def coreachable(cls, dfa):
def coreachable(self):
# least fixpoint
z_current, z_next = set(), set()
z_next = set(dfa.accepting_states)
z_next = set(self.accepting_states)

while z_current != z_next:
z_current = z_next
z_next = deepcopy(z_current)
for state in dfa.states:
for a in dfa.transition_function.get(state, []):
next_state = dfa.transition_function[state][a]
for state in self.states:
for a in self.transition_function.get(state, []):
next_state = self.transition_function[state][a]
if next_state in z_next:
z_next.add(state)
break

new_states = z_current
new_transition_function = {}
for s in new_states:
for a in dfa.transition_function.get(s, []):
next_state = dfa.transition_function[s][a]
for a in self.transition_function.get(s, []):
next_state = self.transition_function[s][a]
if next_state in new_states:
new_transition_function.setdefault(s, {})
new_transition_function[s].setdefault(a, {})
new_transition_function[s][a] = next_state

if dfa.initial_state not in new_states:
if self.initial_state not in new_states:
initial_state = None
else:
initial_state = dfa.initial_state
return DFA(dfa.alphabet, new_states, initial_state, dfa.accepting_states, new_transition_function)
initial_state = self.initial_state
return DFA(self.alphabet, new_states, initial_state, self.accepting_states, new_transition_function)



@classmethod
def trim(cls, dfa):
dfa = DFA.reachable(dfa)
dfa = DFA.coreachable(dfa)
def trim(self):
dfa = self.reachable()
dfa = dfa.coreachable()
return dfa


def word_acceptance(self, word:List[Symbol]):
assert all(char in self.alphabet.symbols for char in word)

current_state = self.initial_state
# return false if current_state is None
if current_state is None:
return False

for char in word:
if char not in self.transition_function[current_state]:
return False
Expand Down
15 changes: 7 additions & 8 deletions pythomata/base/NFA.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,25 @@ def to_dot(self, path):
g.render(filename=path)


@classmethod
def determinize(cls, nfa):
new_states = powerset(nfa.states)
initial_state = nfa.initial_states
final_states = frozenset([q for q in new_states if len(q.intersection(nfa.accepting_states))!=0])
def determinize(self):
new_states = powerset(self.states)
initial_state = frozenset(self.initial_states)
final_states = frozenset([q for q in new_states if len(q.intersection(self.accepting_states)) != 0])
transition_function = {}
for state_set in new_states:
for action in nfa.alphabet.symbols:
for action in self.alphabet.symbols:

next_states = set()
for s in state_set:
for s_prime in nfa.transition_function.get(s, {}).get(action, []):
for s_prime in self.transition_function.get(s, {}).get(action, []):
next_states.add(s_prime)

# next_states = set(s_prime for s in state_set for s_prime in nfa.transition_function.get(s, {}).get(action, []))

next_states = frozenset(next_states)
transition_function.setdefault(state_set, {})[action] = next_states

return DFA(nfa.alphabet, new_states, initial_state, final_states, transition_function)
return DFA(self.alphabet, new_states, initial_state, final_states, transition_function)


@classmethod
Expand Down
4 changes: 2 additions & 2 deletions pythomata/base/Symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def __init__(self, name):
self.name = name

def __str__(self):
return self.name
return str(self.name)

def _members(self):
return (self.name)
Expand All @@ -22,7 +22,7 @@ def __hash__(self):
return hash(self._members())

def __repr__(self):
return ", ".join(map(str,self._members()))
return str(self._members())

def __lt__(self, other):
return self.name.__lt__(other.name)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

setup(
name='pythomata',
version='0.1.dev2',
version='0.1b2',
description="Python implementation of automata.",
long_description=readme + '\n\n' + history,
author="Marco Favorito",
Expand Down
24 changes: 12 additions & 12 deletions tests/automata/nfa_strings.dot
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
digraph {
fake0 [style=invisible]
fake1 [style=invisible]
s2 [shape=doublecircle]
s3 [shape=doublecircle]
s1 [root=true]
s4 [root=true]
s1 [root=true]
s3 [shape=doublecircle]
s2 [shape=doublecircle]
s5
fake1 -> s1 [style=bold]
fake0 -> s4 [style=bold]
s2 -> s1 [label=b]
s3 -> s1 [label=b]
s1 -> s5 [label=c]
s1 -> s2 [label=b]
s1 -> s3 [label=b]
s4 -> s1 [label=c]
fake1 -> s4 [style=bold]
fake0 -> s1 [style=bold]
s4 -> s1 [label=b]
s4 -> s5 [label=b]
s5 -> s5 [label=c]
s4 -> s1 [label=c]
s1 -> s2 [label=b]
s1 -> s3 [label=b]
s1 -> s5 [label=c]
s2 -> s1 [label=b]
s5 -> s5 [label=b]
s5 -> s5 [label=a]
s5 -> s5 [label=c]
s3 -> s1 [label=b]
}
Loading

0 comments on commit b42e5e3

Please sign in to comment.