Exemple #1
0
def get_non_crashing_cover_set(fsm: MealyMachine):
    scs = get_state_cover_set(fsm)
    non_crashing = set()
    for seq in scs:
        fsm.reset()
        output = fsm.process_input(seq)
        if (output is not None) and ("error" not in output):
            non_crashing.add(seq)
    return non_crashing
Exemple #2
0
def get_dset_outputs(fsm, dset):
    states = fsm.get_states()
    outputs = {}
    for state in states:
        mm = MealyMachine(state)
        out = []
        for dseq in dset:
            out.append(mm.process_input(dseq))
            mm.reset()
        outputs[state] = tuple(out.copy())
    return outputs
Exemple #3
0
    def __init__(self, fsm: MealyMachine):
        self.fsm = fsm
        self.A = fsm.get_alphabet()

        self.states = self.fsm.get_states()
        self.root = PartitionNode(self.states, self.A, self)

        self.nodes = [self.root]

        self.wanted = set([state.name for state in fsm.get_states()])
        self.closed = set()
        self.solution = set()
Exemple #4
0
def get_reached_error_states(fsm: MealyMachine):
    reached = set()
    states = fsm.get_states()
    for state in states:
        outputs = list(zip(*state.edges.values()))[1]
        for output in outputs:
            if (match := re.search('error_([0-9]*)', output)) is not None:
                reached.add(int(match.group(1)))
def check_distinguishing_set(fsm, dset):
    states = fsm.get_states()
    outputs = {}
    for state in states:
        mm = MealyMachine(state)
        out = []
        for dseq in dset:
            out.append(mm.process_input(dseq))
            mm.reset()
        outputs[state] = tuple(out.copy())

    if len(set(outputs.values())) < len(outputs):
        print("Not unique", outputs)
        return False
    else:
        print('succes!', len(outputs), 'states,', len(set(outputs)), 'unique outputs')
        return True
Exemple #6
0
def mealy2mcrl2(fsm: MealyMachine, path):

    states = fsm.get_states()

    # Collect the actions performed to put into the act section of the mcrl2 file
    acts = set()

    # Collect the lines to go in the proc section of the mcrl2 file
    proc_lines = []

    # We also need the initial state, for the init line in the mcrl2 file
    init_line = f'init {fsm.initial_state.name};'

    for state in states:
        # Build the line for this state
        state_line = f'{state.name} = '
        first = True

        intermediate_lines = []

        for action, (next_state, output) in state.edges.items():
            # Keep track of actions
            acts.add(action)
            acts.add(output)

            # Transitions to intermediate state
            intermediate_state_name = f'o_{state.name}_{output}'
            state_line += f'{" + " if not first else ""}{action}.{intermediate_state_name}'

            # Transitions from intermediate state to actual next state
            intermediate_lines.append(f'\t{intermediate_state_name} = {output}.{next_state.name};')

            first = False

        if len(state.edges) == 0:
            state_line += 'delta'

        state_line += ';'

        proc_lines.append(state_line)
        proc_lines += intermediate_lines

    with open(path, 'w') as file:
        # Act
        file.write(f'act {", ".join([str(x) for x in acts])};\n\n')

        # Proc
        file.write('proc ')
        for line in proc_lines:
            file.write(f'{line}\n')

        file.write('\n')

        # Init
        file.write(init_line)
Exemple #7
0
def value_iterate(dfa: MealyMachine, gamma, epsilon=0.0001):
    states = dfa.get_states()
    actions = dfa.get_alphabet()

    Q = {}
    Q_1 = {}

    # Initialize Q0
    for sa in product(states, actions):
        Q[sa] = 0

    converged = False
    while not converged:
        # Iterate
        for s, a in product(states, actions):
            next_state, action_result = s.next(a)

            action_reward = 0 if action_result == "end" else int(action_result)
            future_reward = gamma * max([Q[(next_state, next_action)] for next_action in actions])

            Q_1[(s, a)] = action_reward + future_reward

        # Check convergence
        converged = max([abs(Q[sa] - Q_1[sa]) for sa in product(states, actions)]) < epsilon

        Q = Q_1
        Q_1 = {}

    # Annotate states with their values
    for state in states:
        value = max([Q[sa] for sa in product([state], actions)])
        state.name = f'{state.name}/{value:.2f}'

        # Also update the action rewards
        for action in actions:
            next_state, output = state.edges[action]
            state.edges[action] = (next_state, f'{Q[(state, action)]:.2f}')

    dfa.render_graph(tempfile.mktemp('.gv'))
Exemple #8
0
def load_mealy_dot(path, parse_rules=industrial_mealy_parser):
    # Parse the dot file
    context = {'nodes': [], 'edges': []}
    with open(path, 'r') as file:
        for line in file.readlines():
            _parse(parse_rules, line, context)

    # Build the mealy graph
    nodes = {name: MealyState(name) for (name, _) in context['nodes']}
    for (frm, to), edge_properties in context['edges']:
        input, output = edge_properties['label'].strip('"').split('/')
        nodes[frm].add_edge(input, output, nodes[to])
    startnode = nodes[context['start']]

    return MealyMachine(startnode)
Exemple #9
0
def _render(fsm: MealyMachine, filename):
    g = Digraph('G', filename=filename)
    g.attr(rankdir='LR')

    states = fsm.get_states()

    # Add states
    for state in states:
        g.node(state.name)

    # Add transitions:
    for state in states:
        for action, (other_state, output) in state.edges.items():
            g.edge(state.name, other_state.name, label=f'{action}/{output}')

    g.save()
Exemple #10
0
    def build_dfa(self):
        # Gather states from S
        S = self.S

        # The rows can function as index to the 'state' objects
        state_rows = set([tuple(self._get_row(s)) for s in S])
        initial_state_row = tuple(self._get_row(tuple()))

        # Generate state names for convenience
        state_names = {
            state_row: f's{n + 1}'
            for (n, state_row) in enumerate(state_rows)
        }

        # Build the state objects and get the initial and accepting states
        states: Dict[Tuple, MealyState] = {
            state_row: MealyState(state_names[state_row])
            for state_row in state_rows
        }
        initial_state = states[initial_state_row]

        # Add the connections between states
        A = [a for (a, ) in self.A]
        # Keep track of states already visited
        visited_rows = []
        for s in S:
            s_row = tuple(self._get_row(s))
            if s_row not in visited_rows:
                for a in A:
                    if self._is_valid(s + (a, )):
                        sa_row = tuple(self._get_row(s + (a, )))
                        if sa_row in states.keys():
                            try:
                                cur_output = self.query(s + (a, ))
                                states[s_row].add_edge(a, cur_output,
                                                       states[sa_row])
                            except:
                                # Can't add the same edge twice
                                pass
            else:
                visited_rows.append(s_row)

        return MealyMachine(initial_state)
Exemple #11
0
    def construct_hypothesis(self):
        # Keep track of the initial state
        initial_state = self.S[()]

        # Keep track of the amount of states, so we can sift again if
        # the sifting process created a new state
        n = len(list(self.S.items()))
        items_added = True

        # Todo: figure out a neater way to handle missing states during sifting than to just redo the whole thing
        while items_added:
            # Add transitions
            for access_seq, cur_state in list(self.S.items()):
                for a in self.A:
                    next_state = self.sift(access_seq + a)
                    output = self.query(access_seq + a)
                    cur_state.add_edge(a[0], output, next_state, override=True)

            # Check if no new state was added
            n2 = len((self.S.items()))

            items_added = n != n2
            # print("items added", items_added)

            n = n2

        # Add spanning tree transitions
        for access_seq, state in self.S.items():
            if len(access_seq) > 0:
                ancestor_acc_seq = access_seq[0:-1]
                ancestor_state = self.S[ancestor_acc_seq]
                a = access_seq[-1]
                output = self.query(ancestor_acc_seq + (a, ))
                ancestor_state.add_edge(a, output, state, override=True)

        # Find accepting states
        # accepting_states = [state for access_seq, state in self.S.items() if self.query(access_seq)]

        return MealyMachine(initial_state)
Exemple #12
0
def MakeRandomMealyMachine(n_states, A_in, A_out):
    states = [MealyState(f's{x + 1}') for x in range(n_states)]

    def get_reachable(start_state, states):
        to_visit = [start_state]
        visited = []

        while len(to_visit) > 0:
            cur_state = to_visit.pop()
            if cur_state not in visited:
                visited.append(cur_state)

            for action, (other_state, output) in cur_state.edges.items():
                if other_state not in visited and other_state not in to_visit:
                    to_visit.append(other_state)

        return visited, list(set(states).difference(set(visited)))

    def fix_missing(states):
        for state in states:
            for a in A_in:
                if a not in state.edges.keys():
                    state.add_edge(a, "error", state)

    reached, unreached = get_reachable(states[0], states)
    while len(unreached) > 0:
        x = random.choice(reached)
        y = random.choice(unreached)
        a = random.choice(A_in)
        o = random.choice(A_out)

        x.add_edge(a, o, y, override=True)

        reached, unreached = get_reachable(states[0], states)

    fix_missing(states)

    return MealyMachine(states[0])
Exemple #13
0
def minimize(mm: MealyMachine):
    dset = get_distinguishing_set(mm)
    dset_outputs = get_dset_outputs(mm, dset)

    # Find non-unique states:
    state_map = {}
    for state, outputs in dset_outputs.items():
        if outputs not in state_map:
            state_map[outputs] = [state]
        else:
            state_map[outputs].append(state)

    for outputs, states in state_map.items():
        if len(states) > 1:
            og_state = states[0]
            rest_states = states[1:]

            states = mm.get_states()
            for state in states:
                for action, (other_state, output) in state.edges.items():
                    if other_state in rest_states:
                        state.edges[action] = og_state, output

    return mm
Exemple #14
0
def mealy2nusmv_withintermediate(fsm: MealyMachine):

    # Collect fsm info
    states = fsm.get_states()



    alphabet = fsm.get_alphabet()

    inputs = set()
    outputs = set()
    statenames = set()
    initial_state_name = fsm.initial_state.name

    for state in states:
        statenames.add(state.name)
        for input, (next_state, output) in state.edges.items():
            inputs.add(input)
            outputs.add(output)

    # Get a comma separated list of the state names + extra intermediate output states
    # The intermediate states are named *original state name*_o_*input*
    statenames_with_intermediate = []
    for statename in statenames:
        statenames_with_intermediate.append(statename)
        for a in alphabet:
            statenames_with_intermediate.append(f'{statename}_o_{a}')

    statenames_with_intermediate = ",".join(statenames_with_intermediate)

    first_valid_inputs = []
    for input, (next_state, output) in fsm.initial_state.edges.items():
        if output != "invalid_input":
            first_valid_inputs.append(input)

    # Assemble smv file
    smvlines = []
    smvlines.append("MODULE main\n")
    smvlines.append("VAR\n")
    smvlines.append("\tstate : {" + statenames_with_intermediate + "};\n")
    smvlines.append("\toutput: {" + ",".join(outputs) + "," + ",".join(inputs) + "};\n")
    smvlines.append("ASSIGN\n")
    smvlines.append(f"\tinit(state) := {initial_state_name};\n")
    smvlines.append("\tnext(state) := case\n")

    for state in states:
        for input, (next_state, output) in state.edges.items():
            if output != "invalid_input":
                intermediate_name = f'{state.name}_o_{input}'
                smvlines.append(f"\t\t\tstate = {state.name}  & output = {input}: {intermediate_name};\n")
                smvlines.append(f"\t\t\tstate = {intermediate_name} : {next_state.name};\n")

    smvlines.append("\t\t\tTRUE : state;\n")
    smvlines.append("\tesac;\n")

    # The initial inputs also can't be invalid input,
    # So we cannot just choose any alphabet character
    #smvlines.append("\tinit(output) := {" + ",".join(alphabet) + "};\n")
    smvlines.append("\tinit(output) := {" + ",".join(first_valid_inputs) + "};\n")
    smvlines.append("\tnext(output) := case\n")

    for state in states:
        for input, (next_state, output) in state.edges.items():
            if output != "invalid_input":
                intermediate_name = f'{state.name}_o_{input}'
                smvlines.append(f"\t\t\tstate = {state.name} & next(state) = {intermediate_name} : {output};\n")
                valid_next_inputs = [n_input for (n_input, (_, n_output)) in next_state.edges.items()
                                     if n_output != "invalid_input"]
                if len(valid_next_inputs) > 0:
                    smvlines.append(f"\t\t\tstate = {intermediate_name} : " + "{" + ",".join(valid_next_inputs) + "};\n")

    smvlines.append("\t\t\tTRUE : output;\n")

    smvlines.append("\tesac;\n")

    return smvlines
Exemple #15
0
            name_to_c[a] = b
            c_to_name[b] = a

    return name_to_c, c_to_name

if __name__ == "__main__":
    s1 = MealyState('s1')
    s2 = MealyState('s2')
    s3 = MealyState('s3')

    s1.add_edge('a', 'nice', s2)
    s1.add_edge('b', 'a', s1)
    s2.add_edge('a', 'nice', s3)
    s2.add_edge('b', 'back_lol', s1)
    s3.add_edge('a', 'b', s3)
    s3.add_edge('b', 'c', s1)

    mm = MealyMachine(s1)

    constrpath = '/home/tom/projects/lstar/rers/TrainingSeqLtlRers2020/Problem1/constraints-Problem1.txt'
    mappingpath= '/home/tom/projects/lstar/rers/TrainingSeqLtlRers2020/Problem1/Problem1_alphabet_mapping_C_version.txt'

    mealy_lines = mealy2nusmv_withintermediate(mm)
    ltl_lines = rersltl2smv_withintermediate(constrpath, mappingpath)

    with open('test.smv', 'w') as file:
        file.writelines(mealy_lines)
        file.writelines(ltl_lines)

    print('done')
Exemple #16
0
from equivalencecheckers.wmethod import WmethodEquivalenceChecker
from learners.TTTmealylearner import TTTMealyLearner
from suls.mealymachine import MealyState, MealyMachine
from teachers.teacher import Teacher

# Set up an example mealy machine
s1 = MealyState('1')
s2 = MealyState('2')
s3 = MealyState('3')

s1.add_edge('a', 'nice', s2)
s1.add_edge('b', 'B', s1)
s2.add_edge('a', 'nice', s3)
s2.add_edge('b', 'back', s1)
s3.add_edge('a', 'A', s3)
s3.add_edge('b', 'back', s1)

mm = MealyMachine(s1)

# Use the W method equivalence checker
eqc = WmethodEquivalenceChecker(mm, m=len(mm.get_states()))

teacher = Teacher(mm, eqc)

# We are learning a mealy machine
learner = TTTMealyLearner(teacher)

hyp = learner.run()

hyp.render_graph(tempfile.mktemp('.gv'))
learner.DTree.render_graph(tempfile.mktemp('.gv'))
Exemple #17
0
from suls.mealymachine import MealyState, MealyMachine

s1 = MealyState('q0')
s2 = MealyState('q1')
s3 = MealyState('q2')

s1.add_edge('a', '1', s2)
s1.add_edge('b', '0', s1)
s2.add_edge('b', '2', s3)
s2.add_edge('a', '0', s2)
s3.add_edge('a', '3', s3)
s3.add_edge('b', '3', s3)

dfa = MealyMachine(s1)

dfa.render_graph('example_mealy', format='png')
Exemple #18
0
from suls.mealymachine import MealyMachine
from suls.mealymachine import MealyState as State
from util.mealy2nusmv import mealy2nusmv_withintermediate
q0 = State('q0')
q1 = State('q1')

q0.add_edge('a', 'A', q1)

mm = MealyMachine(q0)

for line in mealy2nusmv_withintermediate(mm):
    print(line, end='')
Exemple #19
0
from equivalencecheckers.wmethod import WmethodEquivalenceChecker
from learners.mealylearner import MealyLearner
from suls.mealymachine import MealyState, MealyMachine
from teachers.teacher import Teacher

# Set up an example mealy machine
s1 = MealyState('1')
s2 = MealyState('2')
s3 = MealyState('3')

s1.add_edge('a', 'nice', s2)
s1.add_edge('b', 'B', s1)
s2.add_edge('a', 'nice', s3)
s2.add_edge('b', 'back', s1)
s3.add_edge('a', 'A', s3)
s3.add_edge('b', 'back', s1)

mm = MealyMachine(s1)
mm.render_graph(tempfile.mktemp('.gv'))

# Use the W method equivalence checker
eqc = WmethodEquivalenceChecker(mm)

teacher = Teacher(mm, eqc)

# We are learning a mealy machine
learner = MealyLearner(teacher)

hyp = learner.run()

hyp.render_graph(tempfile.mktemp('.gv'))