def tuple2fts(S, S0, AP, L, Act, trans, name='fts', prepend_str=None): """Create a Finite Transition System from a tuple of fields. Hint ==== To remember the arg order: 1) it starts with states (S0 requires S before it is defined) 2) continues with the pair (AP, L), because states are more fundamental than transitions (transitions require states to be defined) and because the state labeling L requires AP to be defined. 3) ends with the pair (Act, trans), because transitions in trans require actions in Act to be defined. See Also ======== L{tuple2ba} @param S: set of states @type S: iterable of hashables @param S0: set of initial states, must be \\subset S @type S0: iterable of elements from S @param AP: set of Atomic Propositions for state labeling: L: S-> 2^AP @type AP: iterable of hashables @param L: state labeling definition @type L: iterable of (state, AP_label) pairs: [(state0, {'p'} ), ...] | None, to skip state labeling. @param Act: set of Actions for edge labeling: R: E-> Act @type Act: iterable of hashables @param trans: transition relation @type trans: list of triples: [(from_state, to_state, act), ...] where act \\in Act @param name: used for file export @type name: str """ def pair_labels_with_states(states, state_labeling): if state_labeling is None: return if not isinstance(state_labeling, Iterable): raise TypeError('State labeling function: L->2^AP must be ' 'defined using an Iterable.') state_label_pairs = True # cannot be caught by try below if isinstance(state_labeling[0], str): state_label_pairs = False if state_labeling[0] is None: state_label_pairs = False try: (state, ap_label) = state_labeling[0] except: state_label_pairs = False if state_label_pairs: return state_labeling logger.debug('State labeling L not tuples (state, ap_label),\n' 'zipping with states S...\n') state_labeling = zip(states, state_labeling) return state_labeling # args if not isinstance(S, Iterable): raise TypeError('States S must be iterable, even for single state.') # convention if not isinstance(S0, Iterable) or isinstance(S0, str): S0 = [S0] # comprehensive names states = S initial_states = S0 ap = AP state_labeling = pair_labels_with_states(states, L) actions = Act transitions = trans # prepending states with given str if prepend_str: logger.debug('Given string:\n\t' + str(prepend_str) + '\n' + 'will be prepended to all states.') states = prepend_with(states, prepend_str) initial_states = prepend_with(initial_states, prepend_str) ts = FTS() ts.name = name ts.states.add_from(states) ts.states.initial |= initial_states ts.atomic_propositions |= ap # note: verbosity before actions below # to avoid screening by possible error caused by action # state labeling assigned ? if state_labeling is not None: for state, ap_label in state_labeling: if ap_label is None: ap_label = set() ap_label = str2singleton(ap_label) state = prepend_str + str(state) logger.debug('Labeling state:\n\t' + str(state) + '\n' + 'with label:\n\t' + str(ap_label) + '\n') ts.states[state]['ap'] = ap_label # any transition labeling ? if actions is None: for from_state, to_state in transitions: (from_state, to_state) = prepend_with([from_state, to_state], prepend_str) logger.debug('Added unlabeled edge:\n\t' + str(from_state) + '--->' + str(to_state) + '\n') ts.transitions.add(from_state, to_state) else: ts.actions |= actions for from_state, to_state, act in transitions: (from_state, to_state) = prepend_with([from_state, to_state], prepend_str) logger.debug( 'Added labeled edge (=transition):\n\t' + str(from_state) + '---[' + str(act) + ']--->' + str(to_state) + '\n') ts.transitions.add(from_state, to_state, actions=act) return ts
def tuple2ba(S, S0, Sa, Sigma_or_AP, trans, name='ba', prepend_str=None, atomic_proposition_based=True): """Create a Buchi Automaton from a tuple of fields. defines Buchi Automaton by a tuple (S, S0, Sa, \\Sigma, trans) (maybe replacing \\Sigma by AP since it is an AP-based BA ?) See Also ======== L{tuple2fts} @param S: set of states @param S0: set of initial states, must be \\subset S @param Sa: set of accepting states @param Sigma_or_AP: Sigma = alphabet @param trans: transition relation, represented by list of triples:: [(from_state, to_state, guard), ...] where guard \\in \\Sigma. @param name: used for file export @type name: str @rtype: L{BuchiAutomaton} """ # args if not isinstance(S, Iterable): raise TypeError('States S must be iterable, even for single state.') if not isinstance(S0, Iterable) or isinstance(S0, str): S0 = [S0] if not isinstance(Sa, Iterable) or isinstance(Sa, str): Sa = [Sa] # comprehensive names states = S initial_states = S0 accepting_states = Sa alphabet_or_ap = Sigma_or_AP transitions = trans # prepending states with given str if prepend_str: logger.debug('Given string:\n\t' + str(prepend_str) + '\n' + 'will be prepended to all states.') states = prepend_with(states, prepend_str) initial_states = prepend_with(initial_states, prepend_str) accepting_states = prepend_with(accepting_states, prepend_str) ba = BuchiAutomaton(atomic_proposition_based=atomic_proposition_based) ba.name = name ba.states.add_from(states) ba.states.initial |= initial_states ba.states.accepting |= accepting_states if atomic_proposition_based: ba.alphabet.math_set |= alphabet_or_ap else: ba.alphabet.add(alphabet_or_ap) for transition in transitions: (from_state, to_state, guard) = transition [from_state, to_state] = prepend_with([from_state, to_state], prepend_str) # convention if atomic_proposition_based: if guard is None: guard = set() guard = str2singleton(guard) ba.transitions.add(from_state, to_state, letter=guard) return ba
def prepend_with_check(states, prepend_str, expected): assert labeled_graphs.prepend_with(states, prepend_str) == expected