Ejemplo n.º 1
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.º 2
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.º 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(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)