Ejemplo n.º 1
0
def create_state_machine(SM, StateSetList):
    # If all states are of size one, this means, that there were no states that
    # could have been combined. In this case a simple copy of the original
    # state machine will do.
    if filter(lambda state_set: len(state_set) != 1,
              StateSetList.state_set_list) == []:
        return SM.clone()

    # Define a mapping from the state set to a new target state index
    map_new_state_index = {}
    for state_set_index in range(len(StateSetList.state_set_list)):
        map_new_state_index[state_set_index] = state_machine_index.get()

    # The state set that contains the initial state becomes the initial state of
    # the new state machine.
    state_set_containing_initial_state_i = StateSetList.map[
        SM.init_state_index]
    result = StateMachine(
        map_new_state_index[state_set_containing_initial_state_i],
        Core=SM.core())

    # Ensure that each target state index has a state inside the state machine
    for new_state_index in map_new_state_index.values():
        result.create_new_state(StateIdx=new_state_index)

    # Build up the state machine out of the remaining state sets
    state_set_idx = -1L
    for state_set in StateSetList.state_set_list:
        state_set_idx += 1L
        assert len(state_set) != 0, "State set of size '0'. List = " + repr(
            StateSetList)

        # The prototype: States in one set behave all equivalent with respect to target state sets
        # thus only one state from the start set has to be considered.
        prototype = SM.states[state_set[0]]
        # The representive: shall represent the state set in the new state machine.
        representive = result.states[map_new_state_index[state_set_idx]]

        # The representive must have all transitions that the prototype has
        for target_state_index, trigger_set in prototype.transitions().get_map(
        ).items():
            target_state_set_index = StateSetList.map[target_state_index]
            representive.add_transition(
                trigger_set, map_new_state_index[target_state_set_index])

        # Merge all core information of the states inside the state set.
        # If one state set contains an acceptance state, then the result is 'acceptance'.
        # (Note: The initial split separates acceptance states from those that are not
        #  acceptance states. There can be no state set containing acceptance and
        #  non-acceptance states)
        # (Note, that the prototype's info has not been included yet, consider whole set)
        for state_idx in state_set:
            representive.merge(SM.states[state_idx])

    return result
def create_state_machine(SM, StateSetList):
    # If all states are of size one, this means, that there were no states that
    # could have been combined. In this case a simple copy of the original
    # state machine will do.
    if filter(lambda state_set: len(state_set) != 1, StateSetList.state_set_list) == []:
        return SM.clone()
    
    # Define a mapping from the state set to a new target state index
    map_new_state_index = {}
    for state_set_index in range(len(StateSetList.state_set_list)):
        map_new_state_index[state_set_index] = state_machine_index.get()
                
    # The state set that contains the initial state becomes the initial state of 
    # the new state machine.   
    state_set_containing_initial_state_i = StateSetList.map[SM.init_state_index]
    result = StateMachine(map_new_state_index[state_set_containing_initial_state_i],
                          Core = SM.core())

    # Ensure that each target state index has a state inside the state machine
    for new_state_index in map_new_state_index.values():
        result.create_new_state(StateIdx=new_state_index)

    # Build up the state machine out of the remaining state sets
    state_set_idx = -1L
    for state_set in StateSetList.state_set_list:
        state_set_idx += 1L
        assert len(state_set) != 0, "State set of size '0'. List = " + repr(StateSetList)

        # The prototype: States in one set behave all equivalent with respect to target state sets
        # thus only one state from the start set has to be considered.      
        prototype    = SM.states[state_set[0]]
        # The representive: shall represent the state set in the new state machine.
        representive = result.states[map_new_state_index[state_set_idx]]

        # The representive must have all transitions that the prototype has
        for target_state_index, trigger_set in prototype.transitions().get_map().items():
            target_state_set_index = StateSetList.map[target_state_index]
            representive.add_transition(trigger_set, 
                                        map_new_state_index[target_state_set_index])

        # Merge all core information of the states inside the state set.
        # If one state set contains an acceptance state, then the result is 'acceptance'.
        # (Note: The initial split separates acceptance states from those that are not
        #  acceptance states. There can be no state set containing acceptance and 
        #  non-acceptance states) 
        # (Note, that the prototype's info has not been included yet, consider whole set)
        for state_idx in state_set:
            representive.merge(SM.states[state_idx])

    return result    
Ejemplo n.º 3
0
def do(StateMachineList, CommonTerminalStateF=True, CloneF=True):
    """Connect state machines paralell.

       CommonTerminalStateF tells wether the state machines shall trigger 
                            to a common terminal. This is necessary if the
                            state machines are part of a bigger construction.

                            When the ready-to-rumble pattern state machines
                            are to be combined into a single analyzer, the
                            flag must be set to 'False'.

       CloneF               Controls if state machine list is cloned or not.
                            If the single state machines are no longer required after
                            construction, the CloneF can be set to False.

                            If Cloning is disabled the state machines themselves
                            will be altered--which brings some advantage in speed.
    """
    assert type(StateMachineList) == list
    assert len(StateMachineList) != 0
    assert map(lambda x: x.__class__.__name__,
               StateMachineList) == ["StateMachine"] * len(StateMachineList)

    # filter out empty state machines from the consideration
    state_machine_list = filter(lambda sm: not sm.is_empty(), StateMachineList)
    empty_state_machine_occured_f = len(state_machine_list) != len(
        StateMachineList)

    if len(state_machine_list) < 2:
        if len(state_machine_list) < 1: result = StateMachine()
        else: result = state_machine_list[0]
        if empty_state_machine_occured_f:
            result = __add_free_pass(result)
        return result

    # (*) need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    if CloneF:
        clone_list = map(lambda sm: sm.clone(), state_machine_list)
    else:
        clone_list = state_machine_list

    # (*) collect all transitions from both state machines into a single one
    #     (clone to ensure unique identifiers of states)
    result = StateMachine()
    for clone in clone_list:
        result.states.update(clone.states)

    # (*) add additional **init** and **end** state
    #     NOTE: when the result state machine was created, it already contains a
    #           new initial state index. thus at this point only the new terminal
    #           state has to be created.
    #     NOTE: it is essential that the acceptance flag stays False, at this
    #           point in time, so that the mounting operations only happen on
    #           the old acceptance states. Later the acceptance state is raised
    #           to 'accepted' (see below)
    new_terminal_state_index = -1L
    if CommonTerminalStateF:
        new_terminal_state_index = result.create_new_state()

    # (*) Connect from the new initial state to the initial states of the
    #     clones via epsilon transition.
    #     Connect from each success state of the clones to the new end state
    #     via epsilon transition.
    for clone in clone_list:
        result.mount_to_initial_state(clone.init_state_index)
        if CommonTerminalStateF:
            result.mount_to_acceptance_states(new_terminal_state_index,
                                              CancelStartAcceptanceStateF=True,
                                              RaiseTargetAcceptanceStateF=True,
                                              LeaveStoreInputPositionsF=True)

    # (*) If there was an empty state machine, a 'free pass' is added
    if empty_state_machine_occured_f:
        result = __add_free_pass(result, new_terminal_state_index)

    return result
Ejemplo n.º 4
0
def do(StateMachineList, CommonTerminalStateF=True, CloneF=True):
    """Connect state machines paralell.

       CommonTerminalStateF tells wether the state machines shall trigger 
                            to a common terminal. This is necessary if the
                            state machines are part of a bigger construction.

                            When the ready-to-rumble pattern state machines
                            are to be combined into a single analyzer, the
                            flag must be set to 'False'.

       CloneF               Controls if state machine list is cloned or not.
                            If the single state machines are no longer required after
                            construction, the CloneF can be set to False.

                            If Cloning is disabled the state machines themselves
                            will be altered--which brings some advantage in speed.
    """
    assert type(StateMachineList) == list
    assert len(StateMachineList) != 0
    assert map(lambda x: x.__class__.__name__, StateMachineList) == ["StateMachine"] * len(StateMachineList)
              
    # filter out empty state machines from the consideration          
    state_machine_list = filter(lambda sm: not sm.is_empty(), StateMachineList)
    empty_state_machine_occured_f = len(state_machine_list) != len(StateMachineList)

    if len(state_machine_list) < 2:
        if len(state_machine_list) < 1: result = StateMachine()
        else:                           result = state_machine_list[0]
        if empty_state_machine_occured_f:
            result = __add_free_pass(result)
        return result

    # (*) need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    if CloneF:
        clone_list = map(lambda sm: sm.clone(), state_machine_list)
    else:
        clone_list = state_machine_list

    # (*) collect all transitions from both state machines into a single one
    #     (clone to ensure unique identifiers of states)
    result = StateMachine()
    for clone in clone_list:
        result.states.update(clone.states)

    # (*) add additional **init** and **end** state
    #     NOTE: when the result state machine was created, it already contains a 
    #           new initial state index. thus at this point only the new terminal
    #           state has to be created. 
    #     NOTE: it is essential that the acceptance flag stays False, at this
    #           point in time, so that the mounting operations only happen on
    #           the old acceptance states. Later the acceptance state is raised
    #           to 'accepted' (see below)
    new_terminal_state_index = -1L
    if CommonTerminalStateF:
        new_terminal_state_index = result.create_new_state() 
    
    # (*) Connect from the new initial state to the initial states of the
    #     clones via epsilon transition. 
    #     Connect from each success state of the clones to the new end state
    #     via epsilon transition.
    for clone in clone_list:
        result.mount_to_initial_state(clone.init_state_index)
        if CommonTerminalStateF:
            result.mount_to_acceptance_states(new_terminal_state_index,
                                              CancelStartAcceptanceStateF=True,
                                              RaiseTargetAcceptanceStateF=True,
                                              LeaveStoreInputPositionsF=True)


    # (*) If there was an empty state machine, a 'free pass' is added
    if empty_state_machine_occured_f:
        result = __add_free_pass(result, new_terminal_state_index)

    return result
Ejemplo n.º 5
0
def do(the_state_machines):
    """Connect state machines paralell."""
    assert type(the_state_machines) == list
    assert len(the_state_machines) != 0
    assert map(lambda x: x.__class__.__name__, the_state_machines) == ["StateMachine"] * len(the_state_machines)
              
    # filter out empty state machines from the consideration          
    state_machines = filter(lambda sm: not sm.is_empty(), the_state_machines)

    def __add_optional_free_pass(result_state_machine,
                                 TerminationStateIdx=-1):
        """Add an optional 'free pass' if there was an empty state."""  
        # if there was an empty state, then the number of elements in the list changed
        # in case there was an empty state one has to add a 'free pass' from begin to 
        # the final acceptance state.   
        if TerminationStateIdx == -1:
            acceptance_state_index_list = result_state_machine.get_acceptance_state_index_list()
            assert acceptance_state_index_list != [], \
                   "resulting state machine has no acceptance state!"
            TerminationStateIdx = acceptance_state_index_list[0]

        if len(state_machines) != len(the_state_machines):
            result_state_machine.add_epsilon_transition(result_state_machine.init_state_index, 
                                                        TerminationStateIdx)
        return result_state_machine

    if len(state_machines) < 2:
        if len(state_machines) < 1: return __add_optional_free_pass(StateMachine())
        else:                       return __add_optional_free_pass(state_machines[0])

    # (*) need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    clone_list = map(lambda sm: sm.clone(), state_machines)

    # (*) collect all transitions from both state machines into a single one
    #     (clone to ensure unique identifiers of states)
    result = StateMachine()
    for clone in clone_list:
        for start_state_index, states in clone.states.items():        
            # DOUBT: is deepcopy necessary at this place?
            # ANSWER: it does not harm, because no new state indices are creates
            result.states[start_state_index] = deepcopy(states)

    # (*) add additional **init** and **end** state
    #     NOTE: when the result state machine was created, it already contains a 
    #           new initial state index. thus at this point only the new terminal
    #           state has to be created. 
    #     NOTE: it is essential that the acceptance flag stays False, at this
    #           point in time, so that the mounting operations only happen on
    #           the old acceptance states. Later the acceptance state is raised
    #           to 'accepted' (see below)
    new_terminal_state_index = result.create_new_state() 
    
    # (*) connect from the new initial state to the initial states of the
    #     clones via epsilon transition. 
    #     connect from each success state of the clones to the new end state
    #     via epsilon transition.
    for clone in clone_list:
        result.mount_to_initial_state(clone.init_state_index)
        result.mount_to_acceptance_states(new_terminal_state_index,
                                          CancelStartAcceptanceStateF=True,
                                          RaiseTargetAcceptanceStateF=True,
                                          LeaveStoreInputPositionsF=True)


    return __add_optional_free_pass(result, new_terminal_state_index)
Ejemplo n.º 6
0
def do(the_state_machines):
    """Connect state machines paralell."""
    assert type(the_state_machines) == list
    assert len(the_state_machines) != 0
    assert map(
        lambda x: x.__class__.__name__,
        the_state_machines) == ["StateMachine"] * len(the_state_machines)

    # filter out empty state machines from the consideration
    state_machines = filter(lambda sm: not sm.is_empty(), the_state_machines)

    def __add_optional_free_pass(result_state_machine, TerminationStateIdx=-1):
        """Add an optional 'free pass' if there was an empty state."""
        # if there was an empty state, then the number of elements in the list changed
        # in case there was an empty state one has to add a 'free pass' from begin to
        # the final acceptance state.
        if TerminationStateIdx == -1:
            acceptance_state_index_list = result_state_machine.get_acceptance_state_index_list(
            )
            assert acceptance_state_index_list != [], \
                   "resulting state machine has no acceptance state!"
            TerminationStateIdx = acceptance_state_index_list[0]

        if len(state_machines) != len(the_state_machines):
            result_state_machine.add_epsilon_transition(
                result_state_machine.init_state_index, TerminationStateIdx)
        return result_state_machine

    if len(state_machines) < 2:
        if len(state_machines) < 1:
            return __add_optional_free_pass(StateMachine())
        else:
            return __add_optional_free_pass(state_machines[0])

    # (*) need to clone the state machines, i.e. provide their internal
    #     states with new ids, but the 'behavior' remains. This allows
    #     state machines to appear twice, or being used in 'larger'
    #     conglomerates.
    clone_list = map(lambda sm: sm.clone(), state_machines)

    # (*) collect all transitions from both state machines into a single one
    #     (clone to ensure unique identifiers of states)
    result = StateMachine()
    for clone in clone_list:
        for start_state_index, states in clone.states.items():
            # DOUBT: is deepcopy necessary at this place?
            # ANSWER: it does not harm, because no new state indices are creates
            result.states[start_state_index] = deepcopy(states)

    # (*) add additional **init** and **end** state
    #     NOTE: when the result state machine was created, it already contains a
    #           new initial state index. thus at this point only the new terminal
    #           state has to be created.
    #     NOTE: it is essential that the acceptance flag stays False, at this
    #           point in time, so that the mounting operations only happen on
    #           the old acceptance states. Later the acceptance state is raised
    #           to 'accepted' (see below)
    new_terminal_state_index = result.create_new_state()

    # (*) connect from the new initial state to the initial states of the
    #     clones via epsilon transition.
    #     connect from each success state of the clones to the new end state
    #     via epsilon transition.
    for clone in clone_list:
        result.mount_to_initial_state(clone.init_state_index)
        result.mount_to_acceptance_states(new_terminal_state_index,
                                          CancelStartAcceptanceStateF=True,
                                          RaiseTargetAcceptanceStateF=True,
                                          LeaveStoreInputPositionsF=True)

    return __add_optional_free_pass(result, new_terminal_state_index)