from collections import deque from functools import reduce from graphviz import Digraph import re def gap(content, points): return "[gap({points}P)]{gap}[/gap]".format(points=points, gap=content) def p(content): return '<p>{}</p>\n'.format(content) def tex(content): return ('<span class="latex">' + content + '</span>').replace('\\', '\\\\') class NEA: """docstring for NEA""" __slots__ = ['states', 'sigma', 'delta', 'q0', 'F'] def __init__(self, states, sigma, delta, q0, F): self.states = states self.sigma = sigma self.delta = delta self.q0 = q0 self.F = set(F) def to_dea(self): done = [] new_steps = deque([{self.q0}]) table = [] while new_steps: cur = new_steps.popleft() table.append([cur]) for a in self.sigma: next = reduce(lambda a, b: a | b, (self.delta(s, a) for s in cur)) table[-1].append(next) if next not in done: new_steps.append(next) done.append(next) return table def graph_output(self, file_format='svg'): f = Digraph('finite_state_machine', format=file_format, engine='dot') f.body.extend(['rankdir=LR', 'size="8,5"']) f.attr('node', shape='doublecircle') for node in self.F: f.node(node) f.attr('node', shape='circle') f.node('', style='invis') f.edge('', self.q0) for state in self.states: for a in self.sigma: for next in self.delta(state, a): f.edge(str(state), next, label=a) return str(f.pipe(), encoding='utf-8') def generate_form(self): table = self.to_dea() tr = '<tr>\n{}</tr>\n' td = '\t<td>{}</td>\n' aufgabe = '<table border-collapse: collapse; border-style: hidden; rules=\"all\">\n' aufgabe += tr.format(''.join(td.format(s) for s in [tex(r'\delta'), "a", "b"])) for row in table: first, second, third = map(', '.join, (sorted(s) for s in row)) aufgabe += tr.format(td.format(first) + td.format(gap(second, 1)) + td.format(gap(third, 1))) aufgabe += '</table>' return aufgabe def generate_ilias(self): aufgabe = '''Wandeln Sie M in einen DEA M' um, indem Sie die Potenzmenge der Zustände aus M in M' als neue Zustände einfügen (Eine Anleitung befindet sich im Skript von Dr. Müller S. 25).\n\n''' aufgabe += p(self.graph_output()) aufgabe += p('''Füllen Sie diese Tabelle nach dem Vorbild im Müller Skript aus. Achten Sie dabei darauf alle Zustände in lexikographischer Reihenfolge aufzulisten (Zum Beispiel: s1, s2, s4) und alle Zustände müssen mit Komma und Leerzeichen getrennt werden.''') aufgabe += p(self.generate_form()) return aufgabe.replace('"', r'\"') def generate_solution(self): solution = "<h3>Musterloesung</h3><br>" solution += re.sub(r'\[gap\(\d+P\)\](.+)\[\/gap\]', r'\1', self.generate_form()) return solution.replace(r'"', r'\"') # Define one Automaton def delta(state, char): return { ('s0', 'a'): {'s0', 's1'}, ('s0', 'b'): {'s0', 's2'}, ('s1', 'a'): {'s1', 's3'}, ('s1', 'b'): {'s1'}, ('s2', 'a'): {'s2'}, ('s2', 'b'): {'s2', 's3'}, ('s3', 'a'): set(), ('s3', 'b'): set(), }[(state, char)] states = ["s{}".format(i) for i in range(4)] F = ["s3"] # create N = NEA(states, "ab", delta, 's0', F) ### END OF SCRIPT ######################################################## meta = { "type": "GAP", "title": "NEA in DEA umwandeln", "author": "Jan Maximilian Michal", "gapLength": 10, "question": N.generate_ilias(), "solution": N.generate_solution(), }