class WalkAlong(TreeWalker): def __init__(self, SM_A, SM_B, StartingSM=None): self.original = SM_A self.admissible = SM_B if StartingSM is None: self.result = StateMachine(InitStateIndex = index.map_state_combination_to_index((SM_A.init_state_index, SM_B.init_state_index)), InitState = self.get_state_core(SM_A.init_state_index, SM_B.init_state_index)) else: self.result = StartingSM # TODO: Think if 'state_db' cannot be replaced by 'result' self.state_db = {} self.path = [] # Use 'operation_index' to get a unique index that allows to indicate # that 'SM_B' is no longer involved. Also, it ensures that the # generated state indices from (a_state_index, operation_index) are # unique. self.operation_index = index.get() TreeWalker.__init__(self) def on_enter(self, Args): if Args in self.path: return None a_state_index, b_state_index = Args self.path.append((a_state_index, b_state_index)) state = self.get_state(Args) sub_node_list = [] a_tm = self.original.states[a_state_index].target_map.get_map() assert b_state_index != self.operation_index b_tm = self.admissible.states[b_state_index].target_map.get_map() for a_ti, a_trigger_set in a_tm.iteritems(): remainder = a_trigger_set.clone() for b_ti, b_trigger_set in b_tm.iteritems(): # If an acceptance state in 'B' is reached, than the lexeme starts # with something in 'LB'. Thus, rest of paths is inadmissible. if self.admissible.states[b_ti].is_acceptance(): remainder.subtract(b_trigger_set) continue intersection = a_trigger_set.intersection(b_trigger_set) if intersection.is_empty(): continue combi = (a_ti, b_ti) state.add_transition(intersection, index.map_state_combination_to_index(combi)) sub_node_list.append(combi) remainder.subtract(intersection) if not remainder.is_empty(): combi = (a_ti, self.operation_index) state.add_transition(remainder, index.map_state_combination_to_index(combi)) self.result.mount_cloned_subsequent_states(self.original, a_ti, self.operation_index) ## print "#1-sub_node_list:", sub_node_list return sub_node_list def on_finished(self, Node): self.path.pop() def get_state_core(self, AStateIndex, BStateIndex): acceptance_f = self.original.states[AStateIndex].is_acceptance() return State(AcceptanceF=acceptance_f) def get_state(self, Args): state_index = index.map_state_combination_to_index(Args) state = self.state_db.get(state_index) if state is None: a_state_index, b_state_index = Args state = self.get_state_core(a_state_index, b_state_index) self.result.states[state_index] = state return state
class WalkAlong(TreeWalker): def __init__(self, SM_A, SM_B, result=None): self.original = SM_A self.admissible = SM_B if result is None: init_state_index = index.map_state_combination_to_index((SM_A.init_state_index, SM_B.init_state_index)) state = self.get_state_core(SM_A.init_state_index) self.result = StateMachine(InitStateIndex = init_state_index, InitState = state) else: self.result = result self.path = [] # Use 'operation_index' to get a unique index that allows to indicate # that 'SM_B' is no longer involved. Also, it ensures that the # generated state indices from (a_state_index, operation_index) are # unique. self.operation_index = index.get() TreeWalker.__init__(self) def on_enter(self, Args): a_state_index, b_state_index, trigger_set = Args assert b_state_index != self.operation_index if self.is_on_path(Args): return None self.path.append((a_state_index, b_state_index, trigger_set)) a_tm = self.original.states[a_state_index].target_map.get_map() if self.original.states[a_state_index].is_acceptance(): # SM_A has reached a terminal if self.admissible.states[b_state_index].is_acceptance(): # SM_B cuts the path until the terminal. pass else: self.integrate_path_in_result() if len(a_tm) == 0: return None # No further path to walk along b_tm = self.admissible.states[b_state_index].target_map.get_map() #print "#loop:START", a_tm sub_node_list = [] for a_ti, a_trigger_set in a_tm.iteritems(): remainder = a_trigger_set.clone() #print "#a_trigger_set: %s" % a_trigger_set.get_utf8_string() for b_ti, b_trigger_set in b_tm.iteritems(): intersection = a_trigger_set.intersection(b_trigger_set) if intersection.is_empty(): continue #print "#intersection:", intersection.get_utf8_string() sub_node_list.append((a_ti, b_ti, intersection)) remainder.subtract(intersection) #print "#remainder: '%s'" % remainder.get_utf8_string() if not remainder.is_empty(): #print "#B" # SM_B is not involved --> b_ti = self.operation_index self.path.append((a_ti, self.operation_index, remainder)) #print "#result0:", self.result.get_string(NormalizeF=False) self.integrate_path_in_result() self.path.pop() #print "#result1:", self.result.get_string(NormalizeF=False) self.result.mount_cloned_subsequent_states(self.original, a_ti, self.operation_index) #print "#result2:", self.result.get_string(NormalizeF=False) #print "#loop:END", sub_node_list return sub_node_list def on_finished(self, Node): self.path.pop() def is_on_path(self, Args): a_state_index, b_state_index, dummy = Args for ai, bi, dummy in self.path: if ai == a_state_index and bi == b_state_index: return True return False def integrate_path_in_result(self): #print "#integrate_path_in_result:" #for i, x in enumerate(self.path): # try: #print "# [%i] %s, %s, %s" % (i, x[0], x[1], x[2].get_string(Option="utf8")) # except: #print "# [%i] %s" % (i, x) for k, info in r_enumerate(self.path): dummy, bi, dummy = info if bi != self.operation_index and self.admissible.states[bi].is_acceptance(): first_remainder_k = k + 1 # (ai, bi) is cut; next state is good break else: first_remainder_k = 1 if first_remainder_k == len(self.path): # The last element of the path is an acceptance in SM_B, thus it is cut too. return # Nothing left. #print "#first_remainder_k:", first_remainder_k ai, bi, trigger_set = self.path[first_remainder_k] #print "#ai, bi:", ai, bi state_index, state = self.get_state(ai, bi) if state_index != self.result.init_state_index: ##print "#(%s, %s) %s -- epsilon --> %s" % (ai, bi, self.result.init_state_index, state_index) self.result.get_init_state().target_map.add_transition(trigger_set, state_index) #print "#state.target_map:", state.target_map.get_map() #old_ti = state_index for ai, bi, trigger_set in islice(self.path, first_remainder_k+1, None): target_index, target_state = self.get_state(ai, bi) state.add_transition(trigger_set, target_index) #print "# %i -- %s --> %s" % (old_ti, trigger_set.get_utf8_string(), target_index) state = target_state #old_ti = target_index return def get_state_core(self, AStateIndex): acceptance_f = self.original.states[AStateIndex].is_acceptance() return State(AcceptanceF=acceptance_f) def get_state(self, a_state_index, b_state_index): state_index = index.map_state_combination_to_index((a_state_index, b_state_index)) state = self.result.states.get(state_index) if state is None: state = self.get_state_core(a_state_index) self.result.states[state_index] = state #print "#enter:", state_index return state_index, state
class WalkAlong(TreeWalker): def __init__(self, SM_A, SM_B, result=None): self.original = SM_A self.admissible = SM_B if result is None: init_state_index = index.map_state_combination_to_index( (SM_A.init_state_index, SM_B.init_state_index)) state = self.get_state_core(SM_A.init_state_index) self.result = StateMachine(InitStateIndex=init_state_index, InitState=state) else: self.result = result self.path = [] # Use 'operation_index' to get a unique index that allows to indicate # that 'SM_B' is no longer involved. Also, it ensures that the # generated state indices from (a_state_index, operation_index) are # unique. self.operation_index = index.get() TreeWalker.__init__(self) def on_enter(self, Args): a_state_index, b_state_index, trigger_set = Args assert b_state_index != self.operation_index if self.is_on_path(Args): return None self.path.append((a_state_index, b_state_index, trigger_set)) a_tm = self.original.states[a_state_index].target_map.get_map() if self.original.states[a_state_index].is_acceptance(): # SM_A has reached a terminal if self.admissible.states[b_state_index].is_acceptance(): # SM_B cuts the path until the terminal. pass else: self.integrate_path_in_result() if len(a_tm) == 0: return None # No further path to walk along b_tm = self.admissible.states[b_state_index].target_map.get_map() #print "#loop:START", a_tm sub_node_list = [] for a_ti, a_trigger_set in a_tm.iteritems(): remainder = a_trigger_set.clone() #print "#a_trigger_set: %s" % a_trigger_set.get_utf8_string() for b_ti, b_trigger_set in b_tm.iteritems(): intersection = a_trigger_set.intersection(b_trigger_set) if intersection.is_empty(): continue #print "#intersection:", intersection.get_utf8_string() sub_node_list.append((a_ti, b_ti, intersection)) remainder.subtract(intersection) #print "#remainder: '%s'" % remainder.get_utf8_string() if not remainder.is_empty(): #print "#B" # SM_B is not involved --> b_ti = self.operation_index self.path.append((a_ti, self.operation_index, remainder)) #print "#result0:", self.result.get_string(NormalizeF=False) self.integrate_path_in_result() self.path.pop() #print "#result1:", self.result.get_string(NormalizeF=False) self.result.mount_cloned_subsequent_states( self.original, a_ti, self.operation_index) #print "#result2:", self.result.get_string(NormalizeF=False) #print "#loop:END", sub_node_list return sub_node_list def on_finished(self, Node): self.path.pop() def is_on_path(self, Args): a_state_index, b_state_index, dummy = Args for ai, bi, dummy in self.path: if ai == a_state_index and bi == b_state_index: return True return False def integrate_path_in_result(self): #print "#integrate_path_in_result:" #for i, x in enumerate(self.path): # try: #print "# [%i] %s, %s, %s" % (i, x[0], x[1], x[2].get_string(Option="utf8")) # except: #print "# [%i] %s" % (i, x) for k, info in r_enumerate(self.path): dummy, bi, dummy = info if bi != self.operation_index and self.admissible.states[ bi].is_acceptance(): first_remainder_k = k + 1 # (ai, bi) is cut; next state is good break else: first_remainder_k = 1 if first_remainder_k == len(self.path): # The last element of the path is an acceptance in SM_B, thus it is cut too. return # Nothing left. #print "#first_remainder_k:", first_remainder_k ai, bi, trigger_set = self.path[first_remainder_k] #print "#ai, bi:", ai, bi state_index, state = self.get_state(ai, bi) if state_index != self.result.init_state_index: ##print "#(%s, %s) %s -- epsilon --> %s" % (ai, bi, self.result.init_state_index, state_index) self.result.get_init_state().target_map.add_transition( trigger_set, state_index) #print "#state.target_map:", state.target_map.get_map() #old_ti = state_index for ai, bi, trigger_set in islice(self.path, first_remainder_k + 1, None): target_index, target_state = self.get_state(ai, bi) state.add_transition(trigger_set, target_index) #print "# %i -- %s --> %s" % (old_ti, trigger_set.get_utf8_string(), target_index) state = target_state #old_ti = target_index return def get_state_core(self, AStateIndex): acceptance_f = self.original.states[AStateIndex].is_acceptance() return State(AcceptanceF=acceptance_f) def get_state(self, a_state_index, b_state_index): state_index = index.map_state_combination_to_index( (a_state_index, b_state_index)) state = self.result.states.get(state_index) if state is None: state = self.get_state_core(a_state_index) self.result.states[state_index] = state #print "#enter:", state_index return state_index, state