Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 89b44f5

Browse files
Removed my edits from core.py and instead extended Machine to add appropiate functionality. Implemented skeleton for regex
1 parent d43017f commit 89b44f5

File tree

3 files changed

+97
-67
lines changed

3 files changed

+97
-67
lines changed

‎sudkampPython/finiteAutomaton.py‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,39 @@
1-
from sudkampPython.transitions import Machine
1+
from sudkampPython.transitions import Machine, State
2+
3+
class FiniteStateMachine(Machine):
4+
""" An adapted Machine class better suited for use in algorithms. """"
5+
6+
def __init__( *args, **kwargs ):
7+
super(FiniteStateMachine, self).__init__(**kwargs)
8+
9+
self.final_states = set()
10+
11+
@property
12+
def alphabet(self):
13+
return self.events.keys()
14+
15+
@property
16+
def final(self):
17+
""" Return the set of final (or 'accepting') states. """
18+
return self.final_states
19+
20+
def set_final(self, state):
21+
""" Set state as a final (or 'accepting') state. """
22+
if not isinstance(state, State): state = state.name
23+
if state not in self.states:
24+
raise MachineError("Can't set state as final. State not in machine.")
25+
self.final_states.add(state)
26+
27+
def read(self, symbol):
28+
"""
29+
For a transition q0 -[a]-> q1 the stock library can do
30+
machine.a()
31+
machine._process(s.a)
32+
machine.events['a']_trigger()
33+
none of which are particularly good for our purposes. With read() you can simply do
34+
machine.read('a')
35+
"""
36+
return self.events[symbol]._trigger()
237

338
"""
439
Algorithm 5.7.2

‎sudkampPython/regex.py‎

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import itertools
2+
13
"""
24
Algorithm 6.2.2
35
Construction of a Regular Expression from a Finite Automaton
@@ -20,5 +22,31 @@
2022
until the only nodes in G are q0 and qt
2123
2. determine the expression accepted by G
2224
"""
23-
def constructRegExFromFiniteAutomaton( finiteAutomaton ):
24-
raise NotImplementedError
25+
def constructRegExFromFiniteAutomaton( G ):
26+
q0 = G.initial()
27+
qt = list(G.final())[0] # should be only one final state in set
28+
while True:
29+
qi = [x for x in G.states.values() if x.name not in [q0.name, qt.name]][0]
30+
# delete the qi from G according to the following procedure
31+
for j,k in [(j,k) for j,k in list(itertools.product()) if qi.name not in [j.name, k.name])]:
32+
w_ji = [(a,t) for a in G.alphabet for t in nfa.events[a].transitions[j.name] if t.dest == qi.name]
33+
w_ik = [(a,t) for a in G.alphabet for t in nfa.events[a].transitions[qi.name] if t.dest == k.name]
34+
w_ii = [(a,t) for a in G.alphabet for t in nfa.events[a].transitions[qi.name] if t.dest == qi.name]
35+
if w_ji and w_ik and not w_ii:
36+
# add arc from j to k labeled w_ji-w_ik
37+
if w_ji and w_ik and w_ii:
38+
# add arc from j to k labeled w_ji(w_ii)*w_ik
39+
jkArcs = [(a,t) for a in G.alphabet for t in nfa.events[a].transitions[j.name] if t.dest == k.name]
40+
if jkArcs:
41+
newSymbol = '_OR_'.join([a for a,_ in jkArcs]) # union of all symbols
42+
# remove all arcs
43+
for event in G.events.values():
44+
for t in event.transitions.values():
45+
if (t.source == j.name and t.dest == k.name): del event.transitions[t.source]
46+
# replace with new arc
47+
G.add_transition( newSymbol, j.name, k.name)
48+
# remove qi and all arcs incident to it in G
49+
for event in G.events.values():
50+
for t in event.transitions.values():
51+
if qi.name in [t.source,t.dest]: del event.transitions[t.source]
52+
del G.states[qi.name]

‎sudkampPython/transitions/core.py‎

Lines changed: 31 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ def __init__(self, name, on_enter=None, on_exit=None,
3838
callable, or a list of strings.
3939
ignore_invalid_triggers (Boolean): Optional flag to indicate if
4040
unhandled/invalid triggers should raise an exception
41-
4241
"""
4342
self.name = name
4443
self.ignore_invalid_triggers = ignore_invalid_triggers
@@ -70,37 +69,37 @@ def add_callback(self, trigger, func):
7069

7170
class Condition(object):
7271

73-
def __init__(self, func, target=True):
74-
"""
75-
Args:
76-
func (string): Name of the condition-checking callable
77-
target (bool): Indicates the target state--i.e., when True,
78-
the condition-checking callback should return True to pass,
79-
and when False, the callback should return False to pass.
80-
Notes:
81-
This class should not be initialized or called from outside a
82-
Transition instance, and exists at module level (rather than
83-
nesting under the ransition class) only because of a bug in
84-
dill that prevents serialization under Python 2.7.
85-
"""
86-
self.func = func
87-
self.target = target
88-
89-
def check(self, event_data):
90-
""" Check whether the condition passes.
91-
Args:
92-
event_data (EventData): An EventData instance to pass to the
93-
condition (if event sending is enabled) or to extract arguments
94-
from (if event sending is disabled). Also contains the data
95-
model attached to the current machine which is used to invoke
96-
the condition.
97-
"""
98-
predicate = getattr(event_data.model, self.func)
99-
if event_data.machine.send_event:
100-
return predicate(event_data) == self.target
101-
else:
102-
return predicate(
103-
*event_data.args, **event_data.kwargs) == self.target
72+
def __init__(self, func, target=True):
73+
"""
74+
Args:
75+
func (string): Name of the condition-checking callable
76+
target (bool): Indicates the target state--i.e., when True,
77+
the condition-checking callback should return True to pass,
78+
and when False, the callback should return False to pass.
79+
Notes:
80+
This class should not be initialized or called from outside a
81+
Transition instance, and exists at module level (rather than
82+
nesting under the ransition class) only because of a bug in
83+
dill that prevents serialization under Python 2.7.
84+
"""
85+
self.func = func
86+
self.target = target
87+
88+
def check(self, event_data):
89+
""" Check whether the condition passes.
90+
Args:
91+
event_data (EventData): An EventData instance to pass to the
92+
condition (if event sending is enabled) or to extract arguments
93+
from (if event sending is disabled). Also contains the data
94+
model attached to the current machine which is used to invoke
95+
the condition.
96+
"""
97+
predicate = getattr(event_data.model, self.func)
98+
if event_data.machine.send_event:
99+
return predicate(event_data) == self.target
100+
else:
101+
return predicate(
102+
*event_data.args, **event_data.kwargs) == self.target
104103

105104

106105
class Transition(object):
@@ -323,7 +322,6 @@ def __init__(self, model=None, states=None, initial=None, transitions=None,
323322
executed in a state callback function will be queued and executed later.
324323
Due to the nature of the queued processing, all transitions will
325324
_always_ return True since conditional checks cannot be conducted at queueing time.
326-
327325
**kwargs additional arguments passed to next class in MRO. This can be ignored in most cases.
328326
"""
329327

@@ -333,9 +331,7 @@ def __init__(self, model=None, states=None, initial=None, transitions=None,
333331
raise MachineError('Passing arguments {0} caused an inheritance error: {1}'.format(kwargs.keys(), e))
334332

335333
self.model = self if model is None else model
336-
self.alphabet = self.events.keys() # a simple renaming
337334
self.states = OrderedDict()
338-
self.final_states = set()
339335
self.events = {}
340336
self.current_state = None
341337
self.send_event = send_event
@@ -381,11 +377,6 @@ def initial(self):
381377
""" Return the initial state. """
382378
return self._initial
383379

384-
@property
385-
def final(self):
386-
""" Return the set of final (or 'accepting') states """
387-
return self.final_states
388-
389380
@property
390381
def has_queue(self):
391382
""" Return boolean indicating if machine has queue or not """
@@ -395,10 +386,6 @@ def is_state(self, state):
395386
""" Check whether the current state matches the named state. """
396387
return self.current_state.name == state
397388

398-
def is_final(self, state):
399-
""" Check whether the named state is a final state. """
400-
return state in self.final_states
401-
402389
def get_state(self, state):
403390
""" Return the State instance with the passed name. """
404391
if state not in self.states:
@@ -412,12 +399,6 @@ def set_state(self, state):
412399
self.current_state = state
413400
self.model.state = self.current_state.name
414401

415-
def set_final(self, state):
416-
""" Set state as a final ('accepting') state. """
417-
if state not in self.states:
418-
raise MachineError("Can't set state as final. State not in machine.")
419-
self.final_states.add(state)
420-
421402
def add_state(self, *args, **kwargs):
422403
""" Alias for add_states. """
423404
self.add_states(*args, **kwargs)
@@ -563,20 +544,6 @@ def _callback(self, func, event_data):
563544
else:
564545
func(*event_data.args, **event_data.kwargs)
565546

566-
def read(self, symbol):
567-
"""
568-
This has been added to the stock "transitions" library to be a more appropiate
569-
transition handling method for algorithm implementation.
570-
571-
For a transition q0 -[a]-> q1 the stock library can do
572-
machine.a()
573-
machine._process(s.a)
574-
machine.events['a']_trigger()
575-
none of which are particularly good for our purposes. With read() you can simply do
576-
machine.read('a')
577-
"""
578-
return self.events[symbol]._trigger()
579-
580547
def _process(self, trigger):
581548

582549
# default processing

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /