def __init__(self, Candidate): StateA = Candidate.state_a StateB = Candidate.state_b my_index = index.get() self.__state_a = StateA self.__state_b = StateB self.__state_index_sequence = StateA.state_index_sequence( ) + StateB.state_index_sequence() self.__state_index_to_state_key_db = dict( (state_index, i) for i, state_index in enumerate(self.__state_index_sequence)) # Combined DropOut and Entry schemes are generated by the same function entry = TemplateState_Entry(my_index, self.__state_index_to_state_key_db, StateA.entry, StateB.entry) drop_out = MegaState_DropOut(StateA, StateB) MegaState.__init__(self, entry, drop_out, my_index) self.__transition_map, \ self.__target_scheme_n = combine_maps(self.__state_a, self.__state_b) # Compatible with AnalyzerState # (A template state can never mimik an init state) self.__engine_type = None # StateA.engine_type # self.input = None # StateA.input # get_input_action(StateA.engine_type, InitStateF=False) MegaState.bad_company_set( self, self.__state_a.bad_company().union(self.__state_b.bad_company()))
def __init__(self, StartState, StartCharacter, AdaptedTransitionMap): if StartState is None: return # Only for Clone assert StartState is None or isinstance(StartState, AnalyzerState) assert StartCharacter is None or isinstance(StartCharacter, (int, long)) assert AdaptedTransitionMap is None or isinstance(AdaptedTransitionMap, list) self.index = index.get() self.entry = PathWalkerState_Entry(self.index, StartState.entry) self.drop_out = MegaState_DropOut(StartState) self.__sequence = [ CharacterPathElement(StartState.index, StartCharacter) ] self.__transition_map = AdaptedTransitionMap # Set the 'void' target to indicate wildcard. self.__wildcard_char = StartCharacter transition_map_tools.set(self.__transition_map, StartCharacter, E_StateIndices.VOID)
def __init__(self, StartState, StartCharacter, AdaptedTransitionMap): assert StartState is None or isinstance(StartState, AnalyzerState) assert StartCharacter is None or isinstance(StartCharacter, (int, long)) assert AdaptedTransitionMap is None or isinstance(AdaptedTransitionMap, list) if StartState is None: return # Only for Clone self.index = index.get() self.entry = PathWalkerState_Entry(self.index, StartState.entry) self.drop_out = MegaState_DropOut(StartState) self.__sequence = [ CharacterPathElement(StartState.index, StartCharacter) ] self.__transition_map = AdaptedTransitionMap # Set the 'void' target to indicate wildcard. transition_map_tools.set(self.__transition_map, StartCharacter, E_StateIndices.VOID) self.__wildcard_char = StartCharacter
class CharacterPath(object): """________________________________________________________________________ A chain of states that can be walked along with a character sequence plus a common remaining transition map. ___________________________________________________________________________ """ __slots__ = ("index", "entry", "drop_out", "__sequence", "__transition_map", "__wildcard_char") def __init__(self, StartState, StartCharacter, AdaptedTransitionMap): if StartState is None: return # Only for Clone assert StartState is None or isinstance(StartState, AnalyzerState) assert StartCharacter is None or isinstance(StartCharacter, (int, long)) assert AdaptedTransitionMap is None or isinstance(AdaptedTransitionMap, list) self.index = index.get() self.entry = PathWalkerState_Entry(self.index, StartState.entry) self.drop_out = MegaState_DropOut(StartState) self.__sequence = [ CharacterPathElement(StartState.index, StartCharacter) ] self.__transition_map = AdaptedTransitionMap # Set the 'void' target to indicate wildcard. self.__wildcard_char = StartCharacter transition_map_tools.set(self.__transition_map, StartCharacter, E_StateIndices.VOID) def clone(self): result = CharacterPath(None, None, None) result.index = self.index result.entry = self.entry result.drop_out = self.drop_out result.__sequence = [x.clone() for x in self.__sequence] def adapt(Target): if hasattr(Target, "clone"): return Target.clone() else: return Target result.__transition_map = [(interval.clone(), adapt(target)) for interval, target in self.__transition_map] result.__wildcard_char = self.__wildcard_char return result @property def state_index_set(self): """Result **MUST** be a list, because, later on a state key may be associated with it. """ assert len(self.__sequence) > 1 return set(x.state_index for x in self.__sequence[:-1]) def has_wildcard(self): return self.__wildcard_char is not None def sequence(self): return self.__sequence @property def transition_map(self): return self.__transition_map def end_state_index(self): if len(self.__sequence) == 0: return -1 return self.__sequence[-1].state_index def append_state(self, State, TransitionCharacterToNextState=None): """Append 'State' to path: -- add 'State' to the sequence of states on the path. -- absorb the 'State's' drop-out and entry actions into the path's drop-out and entry actions. If 'TransitionCharacterToNextState' is None, then the state is considered a terminal state. Terminal states are not themselves implemented inside a PathWalkerState. Thus, their entry and drop out information does not have to be absorbed. Terminal states are indicated in the 'sequence' by a 'transition_char_to_next' of 'None' (which corresponds well with the aforementioned). """ # The index of the state on the path determines the path iterator's offset offset = len(self.__sequence) # Add the state on the sequence of state along the path self.__sequence.append(CharacterPathElement(State.index, TransitionCharacterToNextState)) if TransitionCharacterToNextState is not None: # Adapt the entry's action_db: include the entries of the new state self.entry.action_db_update(State.entry, offset) # Adapt information about entry and drop-out actions self.drop_out.update_from_state(State) def get_uniform_entry_command_list_along_path(self): """When a state is entered (possibly) some commands are executed, for example 'position[1] = input_p' or 'last_acceptance = 13'. The states on the path may require also actions to be taken when walking along the path. This function determines whether those commands are always the same or not. THIS DOES NOT INCLUDE THE TERMINAL STATE! THE ENTRY OF THE TERMINAL STATE IS NOT PART OF THE PATHWALKER! RETURNS: ComandList -- if the commands are uniform. None -- if the commands are not uniform. """ # A path where there are not at least two states, is not a path. assert len(self.__sequence) >= 2 prev_state_index = self.__sequence[0].state_index prototype = None for x in self.__sequence[1:-1]: action = self.entry.action_db_get_command_list(x.state_index, prev_state_index) if prototype is not None: if not prototype.is_equivalent(action.command_list): return None else: prototype = action.command_list.clone() prototype.delete_SetPathIterator_commands() prev_state_index = x.state_index # Since len(sequence) >= 2, then there is a 'prototype' at this point. return prototype def contains_state(self, StateIndex): for dummy in ifilter(lambda x: x.state_index == StateIndex, self.__sequence): return True return False def check_uniform_entry_to_state(self, State): """Checks whether the entry from the end of the path to the state would be uniform with the entries along the path. RETURNS: True -- State would be entered through the same entry as all the other states on the path. False -- State would require a separate entry, because some commands need to be executed that are not done for all other transitions on the path. """ if len(self.__sequence) < 2: # The 'State' will be the first entry along the path, so it can only # be uniform. There is simply no other entry. return True uniform_entry = self.get_uniform_entry_command_list_along_path() if uniform_entry is None: # Actually, this could be an assert. This function is only return False # to be executed when building uniform paths. action = self.entry.action_db_get_command_list(State.index, self.__sequence[-1].state_index) if not uniform_entry.is_equivalent(action.command_list): return False return True def match(self, TransitionMap, TargetDoorID, TriggerCharToTarget): """A single character transition TriggerCharToTarget --> DoorID has been detected. The question is, if the remaining transitions of the state match the transition map of the current path. There might be a wild card, that is the character that is overlapped by the first single character transition. As long as a transition map differs only by this single character, the wild card is plugged into the position. RETURNS: int > 0, the character that the wild card shall take so that the path's transition map matches the TransitionMap. - 1, if path's transition map and TransitionMap match anyway and no wild card plug is necessary. None, if there is no way that the path's transition map and the TransitionMap could match. """ wildcard_target = -1 for begin, end, a_target, b_target in transition_map_tools.zipped_iterable(self.__transition_map, TransitionMap): if a_target == b_target: continue # There is no problem at all size = end - begin assert size > 0 if size == 1: if b_target == TargetDoorID: continue elif a_target == E_StateIndices.VOID: wildcard_target = b_target; continue else: return None else: return None # Here: The transition maps match, but possibly require the use of a wildcard. return wildcard_target def get_sibling(self, StateIndex, TransitionChar, Other): """The 'Other' path intersects at 'StateIndex' with this path (StateIndex can only appear once in path, since recursion is not possible). This function generates a sibling where the Other path is docked to this path at the position of 'StateIndex'. """ assert self.__wildcard_char is None # As long as there is a wildcard, the assert Other.__wildcard_char is None # transition map is not frozen. # # => No siblings can be determined. for i, x in self.__sequence: if x.state_index == StateIndex: break else: assert False, "StateIndex must be part of path." new_sequence = Other.sequence() \ + [ CharacterPathElement(StateIndex, TransitionChar) ] \ + self.__sequence[:i+1] return CharacterPathElement(new_sequence) def finalize(self): # Ensure that there is no wildcard in the transition map if self.__wildcard_char is None: return transition_map_tools.smoothen(self.__transition_map, self.__wildcard_char) self.__wildcard_char = None def plug_wildcard(self, Target): assert isinstance(Target, DoorID) or Target == E_StateIndices.DROP_OUT, repr(Target) assert self.__wildcard_char is not None assert transition_map_tools.get_target(self.__transition_map, self.__wildcard_char) == E_StateIndices.VOID transition_map_tools.set(self.__transition_map, self.__wildcard_char, Target) self.__wildcard_char = None return def get_string(self, NormalizeDB=None): # assert NormalizeDB is None, "Sorry, I guessed that this was no longer used." def norm(X): assert isinstance(X, (int, long)) or X is None return X if NormalizeDB is None else NormalizeDB[X] L = max(len(x[0].get_utf8_string()) for x in self.__transition_map) skeleton_txt = "" for interval, target_door_id in self.__transition_map: interval_str = interval.get_utf8_string() skeleton_txt += " %s%s -> %s\n" % (interval_str, " " * (L - len(interval_str)), target_door_id) sequence_txt = "" for x in self.__sequence[:-1]: sequence_txt += "(%i)--'%s'-->" % (x.state_index, chr(x.transition_char_to_next)) sequence_txt += "[%i]" % norm(self.__sequence[-1].state_index) return "".join(["start = %i;\n" % norm(self.__sequence[0].state_index), "path = %s;\n" % sequence_txt, "skeleton = {\n%s}\n" % skeleton_txt, "wildcard = %s;\n" % repr(self.__wildcard_char is not None)]) def __repr__(self): return self.get_string() def __len__(self): return len(self.__sequence)