Loading demo.py +11 −5 Original line number Diff line number Diff line Loading @@ -9,7 +9,8 @@ def make_dfa(states: Set[str], characters: Set[str], new_init = State(init) new_states: Set[State] = set() dfa = DFA(new_states.add(new_init), set(), {}, new_init, set()) new_states.add(new_init) dfa = DFA(new_states, set(), {}, new_init, set()) for name in states: state = State(name) Loading Loading @@ -181,16 +182,21 @@ def main(): print(parser.dfa_to_str(dfa_4, True)) print() dfareg = dfa_4.dfa_to_reg() print("DFA transformated to REG:") print("DFA transformed to REG:") print(parser.reg_to_str(dfareg, True)) print() regdfa = dfareg.reg_to_nfa() print("REG transformated to NFA:") print("REG transformed to NFA:") print(parser.nfa_to_str(regdfa, True)) print() #det = nfa1.determinize() #print(parser.dfa_to_str(det, True)) print("__________________________________") print("NFA.determinize()") print("Determinization of NFA to DFA:") det = nfa1.determinize() print(parser.nfa_to_str(nfa1, True)) print() print(parser.dfa_to_str(det, True)) print("__________________________________") print("DFA.is_equivalent()") Loading objects.py +31 −38 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, List, Dict, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from enum import Enum import enum from copy import deepcopy Loading Loading @@ -69,7 +69,7 @@ class State: class REG: Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon Loading Loading @@ -97,7 +97,7 @@ class REG: for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if type(rule) == Terminal: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name Loading Loading @@ -129,7 +129,7 @@ class REG: for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if type(rule) == Terminal: # TODO and a is not \eps if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) Loading Loading @@ -186,7 +186,8 @@ class DFA: for (state, character) in self.transition: assert state in self.states, "unknown state " + state.name assert character in self.characters, "unknown character " + character.name assert self.transition[state, character] in self.states, "unknown state " + self.transition[state, character].name assert self.transition[state, character] in self.states, "unknown state " + self.transition[ state, character].name assert self.init in self.states, "init not in states" for state in self.final: Loading Loading @@ -331,17 +332,8 @@ class DFA: return dfa # TODO sorted(set, key = lambda x: x.name) sorted_terminals def sort_characters(self) -> List[Character]: to_sort = list(deepcopy(self.characters)) names = [] for character in to_sort: names.append((character.name, character)) names.sort() sorted_characters = [] for name, character in names: sorted_characters.append(character) return sorted_characters return sorted(self.characters, key=lambda x: x.name) def minimize(self) -> DFA: dfa = deepcopy(self) Loading Loading @@ -450,7 +442,7 @@ class DFA: def dfa_to_reg(self) -> REG: nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] = dict() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() for state in self.states: nonterminal = Nonterminal(state.name) Loading @@ -473,7 +465,7 @@ class DFA: else: rules[init] = {(terminal, nonterminal2)} if move in self.final: rules[init].add((terminal)) rules[init].add(terminal) else: nonterminal1 = Nonterminal(state.name) nonterminal2 = Nonterminal(move.name) Loading Loading @@ -508,7 +500,7 @@ class DFA: # Ha! def is_universal(self): return self.is_empty(self.complement()) return self.complement().is_empty() def is_equivalent(self, dfa: DFA) -> bool: self.complement() Loading Loading @@ -543,42 +535,43 @@ class NFA: self.final = self.set_or_none(final) def determinize(self) -> DFA: states = set(frozenset({self.init})) states: Set[FrozenSet[State]] = set() states.add(frozenset({self.init})) transition = {} final = set() done: Set[State] = set() done: Set[FrozenSet[State]] = set() todo = states.difference(done) while len(todo) > 0: subset = iter(todo).next() # arbitrary element from set if subset.difference(self.final) > 0: while len(states.difference(done)) > 0: subset = (states.difference(done)).pop() # arbitrary element from set if len(subset.intersection(self.final)) > 0: final.add(subset) for character in self.characters: new_subset = set() new_subset: Set[State] = set() for state in subset: if (state, character) in self.transition: new_subset.add(self.transition[state, character]) states.add(new_subset) transition[subset, character] = new_subset new_subset = new_subset.union(self.transition[state, character]) states.add(frozenset(new_subset)) transition[subset, character] = frozenset(new_subset) done.add(subset) new_states: Set[State] = set() new_transition: Dict[Tuple[State, Character], State] = dict() new_final: Set[State] = set() for state in states: new_states.add(self.unset(state)) for state in final: new_final.add(self.unset(state)) for state, character in transition: new_transition[self.unset(state), character] = self.unset(self.transition[state, character]) for state_set in states: new_states.add(self.unset(state_set)) for state_set in final: new_final.add(self.unset(state_set)) for state_set, character in transition: new_transition[self.unset(state_set), character] = self.unset(transition[state_set, character]) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) return dfa def unset(self, states: Set[State]) -> State: return State('_'.join(set(map(lambda x: x.name, states)))) def unset(self, states: FrozenSet[State]) -> State: return State('_'.join(set(map(lambda x: x.name, sorted(states, key=lambda x: x.name))))) # would be function for in epsilon NFA def eliminate_epsilon(self) -> NFA: Loading parser.py +8 −8 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re from objects import REG, DFA, Terminal from objects import REG, DFA, NFA, Terminal # TODO ask: commas at the ends of lines or not? Loading Loading @@ -38,7 +38,7 @@ class Parser: out += (rule.name + "->") for variant in rewrite: if type(variant) == Terminal: if isinstance(variant, Terminal): out += variant.name else: for i in range(len(variant)): Loading Loading @@ -88,24 +88,24 @@ class Parser: return transition + "\n" + final def nfa_to_str(self, dfa: DFA, full : bool = False) -> str: def nfa_to_str(self, nfa: NFA, full : bool = False) -> str: # full - verbose description of DFA - only for development, dismiss later states = "{" for state in dfa.states: for state in nfa.states: states += state.name + "," states = states[:-1] + "}" # Vlada: states = ",".join(dfa.states) but I use it wrong or what characters = "{" for character in dfa.characters: for character in nfa.characters: characters += character.name + "," characters = characters[:-1] + "}" transition = "" for key, set_states in dfa.transition.items(): for key, set_states in nfa.transition.items(): state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")={" for state in set_states: Loading @@ -113,10 +113,10 @@ class Parser: transition = transition[:-1] + "}\n" transition = "{" + transition[:-1] + "}" init = dfa.init.name init = nfa.init.name final = "F={" for state in dfa.final: for state in nfa.final: final += state.name + "," final = final[:-1] + "}" Loading Loading
demo.py +11 −5 Original line number Diff line number Diff line Loading @@ -9,7 +9,8 @@ def make_dfa(states: Set[str], characters: Set[str], new_init = State(init) new_states: Set[State] = set() dfa = DFA(new_states.add(new_init), set(), {}, new_init, set()) new_states.add(new_init) dfa = DFA(new_states, set(), {}, new_init, set()) for name in states: state = State(name) Loading Loading @@ -181,16 +182,21 @@ def main(): print(parser.dfa_to_str(dfa_4, True)) print() dfareg = dfa_4.dfa_to_reg() print("DFA transformated to REG:") print("DFA transformed to REG:") print(parser.reg_to_str(dfareg, True)) print() regdfa = dfareg.reg_to_nfa() print("REG transformated to NFA:") print("REG transformed to NFA:") print(parser.nfa_to_str(regdfa, True)) print() #det = nfa1.determinize() #print(parser.dfa_to_str(det, True)) print("__________________________________") print("NFA.determinize()") print("Determinization of NFA to DFA:") det = nfa1.determinize() print(parser.nfa_to_str(nfa1, True)) print() print(parser.dfa_to_str(det, True)) print("__________________________________") print("DFA.is_equivalent()") Loading
objects.py +31 −38 Original line number Diff line number Diff line from __future__ import annotations from typing import Set, List, Dict, Tuple, Deque, Optional, TypeVar from typing import Set, FrozenSet, List, Dict, Union, Tuple, Deque, Optional, TypeVar from enum import Enum import enum from copy import deepcopy Loading Loading @@ -69,7 +69,7 @@ class State: class REG: Rules = Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] Rules = Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] type_var = TypeVar('type_var') # TODO should accept init -> epsilon Loading Loading @@ -97,7 +97,7 @@ class REG: for nonterminal in self.rules: assert nonterminal in self.nonterminals, "unknown nonterminal " + nonterminal.name for rule in self.rules[nonterminal]: if type(rule) == Terminal: if isinstance(rule, Terminal): assert rule in self.terminals, "unknown terminal " + rule.name else: assert rule[0] in self.terminals, "unknown terminal " + rule[0].name Loading Loading @@ -129,7 +129,7 @@ class REG: for rule in self.rules[nonterminal]: # rule A -> a becomes d(A, a) = final if type(rule) == Terminal: # TODO and a is not \eps if isinstance(rule, Terminal): # TODO and a is not \eps character = Character(rule.name) if (state, character) in transition: transition[state, character].add(final) Loading Loading @@ -186,7 +186,8 @@ class DFA: for (state, character) in self.transition: assert state in self.states, "unknown state " + state.name assert character in self.characters, "unknown character " + character.name assert self.transition[state, character] in self.states, "unknown state " + self.transition[state, character].name assert self.transition[state, character] in self.states, "unknown state " + self.transition[ state, character].name assert self.init in self.states, "init not in states" for state in self.final: Loading Loading @@ -331,17 +332,8 @@ class DFA: return dfa # TODO sorted(set, key = lambda x: x.name) sorted_terminals def sort_characters(self) -> List[Character]: to_sort = list(deepcopy(self.characters)) names = [] for character in to_sort: names.append((character.name, character)) names.sort() sorted_characters = [] for name, character in names: sorted_characters.append(character) return sorted_characters return sorted(self.characters, key=lambda x: x.name) def minimize(self) -> DFA: dfa = deepcopy(self) Loading Loading @@ -450,7 +442,7 @@ class DFA: def dfa_to_reg(self) -> REG: nonterminals: Set[Nonterminal] = set() terminals: Set[Terminal] = set() rules: Dict[Nonterminal, Set[Tuple[Terminal, Optional[Nonterminal]]]] = dict() rules: Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict() for state in self.states: nonterminal = Nonterminal(state.name) Loading @@ -473,7 +465,7 @@ class DFA: else: rules[init] = {(terminal, nonterminal2)} if move in self.final: rules[init].add((terminal)) rules[init].add(terminal) else: nonterminal1 = Nonterminal(state.name) nonterminal2 = Nonterminal(move.name) Loading Loading @@ -508,7 +500,7 @@ class DFA: # Ha! def is_universal(self): return self.is_empty(self.complement()) return self.complement().is_empty() def is_equivalent(self, dfa: DFA) -> bool: self.complement() Loading Loading @@ -543,42 +535,43 @@ class NFA: self.final = self.set_or_none(final) def determinize(self) -> DFA: states = set(frozenset({self.init})) states: Set[FrozenSet[State]] = set() states.add(frozenset({self.init})) transition = {} final = set() done: Set[State] = set() done: Set[FrozenSet[State]] = set() todo = states.difference(done) while len(todo) > 0: subset = iter(todo).next() # arbitrary element from set if subset.difference(self.final) > 0: while len(states.difference(done)) > 0: subset = (states.difference(done)).pop() # arbitrary element from set if len(subset.intersection(self.final)) > 0: final.add(subset) for character in self.characters: new_subset = set() new_subset: Set[State] = set() for state in subset: if (state, character) in self.transition: new_subset.add(self.transition[state, character]) states.add(new_subset) transition[subset, character] = new_subset new_subset = new_subset.union(self.transition[state, character]) states.add(frozenset(new_subset)) transition[subset, character] = frozenset(new_subset) done.add(subset) new_states: Set[State] = set() new_transition: Dict[Tuple[State, Character], State] = dict() new_final: Set[State] = set() for state in states: new_states.add(self.unset(state)) for state in final: new_final.add(self.unset(state)) for state, character in transition: new_transition[self.unset(state), character] = self.unset(self.transition[state, character]) for state_set in states: new_states.add(self.unset(state_set)) for state_set in final: new_final.add(self.unset(state_set)) for state_set, character in transition: new_transition[self.unset(state_set), character] = self.unset(transition[state_set, character]) dfa = DFA(new_states, self.characters, new_transition, self.init, new_final) return dfa def unset(self, states: Set[State]) -> State: return State('_'.join(set(map(lambda x: x.name, states)))) def unset(self, states: FrozenSet[State]) -> State: return State('_'.join(set(map(lambda x: x.name, sorted(states, key=lambda x: x.name))))) # would be function for in epsilon NFA def eliminate_epsilon(self) -> NFA: Loading
parser.py +8 −8 Original line number Diff line number Diff line from typing import List, Dict, Tuple, Optional import re from objects import REG, DFA, Terminal from objects import REG, DFA, NFA, Terminal # TODO ask: commas at the ends of lines or not? Loading Loading @@ -38,7 +38,7 @@ class Parser: out += (rule.name + "->") for variant in rewrite: if type(variant) == Terminal: if isinstance(variant, Terminal): out += variant.name else: for i in range(len(variant)): Loading Loading @@ -88,24 +88,24 @@ class Parser: return transition + "\n" + final def nfa_to_str(self, dfa: DFA, full : bool = False) -> str: def nfa_to_str(self, nfa: NFA, full : bool = False) -> str: # full - verbose description of DFA - only for development, dismiss later states = "{" for state in dfa.states: for state in nfa.states: states += state.name + "," states = states[:-1] + "}" # Vlada: states = ",".join(dfa.states) but I use it wrong or what characters = "{" for character in dfa.characters: for character in nfa.characters: characters += character.name + "," characters = characters[:-1] + "}" transition = "" for key, set_states in dfa.transition.items(): for key, set_states in nfa.transition.items(): state_1, terminal = key transition += "(" + state_1.name + "," + terminal.name + ")={" for state in set_states: Loading @@ -113,10 +113,10 @@ class Parser: transition = transition[:-1] + "}\n" transition = "{" + transition[:-1] + "}" init = dfa.init.name init = nfa.init.name final = "F={" for state in dfa.final: for state in nfa.final: final += state.name + "," final = final[:-1] + "}" Loading