def generate_random_mealy_machine(num_states, input_alphabet, output_alphabet, compute_prefixes=False) -> MealyMachine: """ Generates a random Mealy machine. Args: num_states: number of states input_alphabet: input alphabet output_alphabet: output alphabet compute_prefixes: if true, shortest path to reach each state will be computed (Default value = False) Returns: Mealy machine with num_states states """ states = list() for i in range(num_states): states.append(MealyState(i)) for state in states: for a in input_alphabet: state.transitions[a] = random.choice(states) state.output_fun[a] = random.choice(output_alphabet) mm = MealyMachine(states[0], states) if compute_prefixes: for state in states: state.prefix = mm.get_shortest_path(mm.initial_state, state) return mm
def mealy_from_state_setup(state_setup) -> MealyMachine: """ First state in the state setup is the initial state. state_setup = { "a": {"x": ("o1", "b1"), "y": ("o2", "a")}, "b1": {"x": ("o3", "b2"), "y": ("o1", "a")}, "b2": {"x": ("o1", "b3"), "y": ("o2", "a")}, "b3": {"x": ("o3", "b4"), "y": ("o1", "a")}, "b4": {"x": ("o1", "c"), "y": ("o4", "a")}, "c": {"x": ("o3", "a"), "y": ("o5", "a")}, } Args: state_setup: state_setup should map from state_id to tuple(transitions_dict). Returns: Mealy Machine """ # state_setup should map from state_id to tuple(transitions_dict). # Each entry in transition dict is <input> : <output, new_state_id> # build states with state_id and output states = {key: MealyState(key) for key, _ in state_setup.items()} # add transitions to states for state_id, state in states.items(): for _input, (output, new_state) in state_setup[state_id].items(): state.transitions[_input] = states[new_state] state.output_fun[_input] = output # states to list states = [state for state in states.values()] # build moore machine with first state as starting state mm = MealyMachine(states[0], states) for state in states: state.prefix = mm.get_shortest_path(mm.initial_state, state) return mm
def gen_hypothesis(self, check_for_duplicate_rows=False) -> Automaton: """ Generate automaton based on the values found in the observation table. :return: Args: check_for_duplicate_rows: (Default value = False) Returns: Automaton of type `automaton_type` """ state_distinguish = dict() states_dict = dict() initial_state = None automaton_class = { 'dfa': Dfa, 'mealy': MealyMachine, 'moore': MooreMachine } # delete duplicate rows, only possible if no counterexample processing is present # counterexample processing removes the need for consistency check, as it ensures # that no two rows in the S set are the same if check_for_duplicate_rows: rows_to_delete = set() for i, s1 in enumerate(self.S): for s2 in self.S[i + 1:]: if self.T[s1] == self.T[s2]: rows_to_delete.add(s2) for row in rows_to_delete: self.S.remove(row) # create states based on S set stateCounter = 0 for prefix in self.S: state_id = f's{stateCounter}' if self.automaton_type == 'dfa': states_dict[prefix] = DfaState(state_id) states_dict[prefix].is_accepting = self.T[prefix][0] elif self.automaton_type == 'moore': states_dict[prefix] = MooreState(state_id, output=self.T[prefix][0]) else: states_dict[prefix] = MealyState(state_id) states_dict[prefix].prefix = prefix state_distinguish[tuple(self.T[prefix])] = states_dict[prefix] if not prefix: initial_state = states_dict[prefix] stateCounter += 1 # add transitions based on extended S set for prefix in self.S: for a in self.A: state_in_S = state_distinguish[self.T[prefix + a]] states_dict[prefix].transitions[a[0]] = state_in_S if self.automaton_type == 'mealy': states_dict[prefix].output_fun[a[0]] = self.T[prefix][ self.E.index(a)] automaton = automaton_class[self.automaton_type]( initial_state, list(states_dict.values())) automaton.characterization_set = self.E return automaton