def evaluateNFA(): print("Eval NFA") # NFA which matches strings beginning with 'a', ending with 'a', and containing # no consecutive 'b's value = str(mainWidget.lineEdit_eval.text()) nfa = NFA( # states=getStates(), # input_symbols=symbols, # transitions={ # 'q0': {'a': {'q1'}}, # # Use '' as the key name for empty string (lambda/epsilon) transitions # 'q1': {'a': {'q1'}, '': {'q2'}}, # 'q2': {'b': {'q0'}} # }, # initial_state='q0', # final_states={'q1'} states=getStates(), input_symbols=symbols, transitions=getNFATransitions(), initial_state=str(startNode.label.text()), final_states=getFinalStates()) try: listStates = list(nfa.validate_input(value, step=True)) print(str(listStates)) showMsg("NFA Successful, Last:" + str(nfa.validate_input(value))) except: showMsg("ERROR EVALUATING NFA") return nfa
def test_kleene_star(self): # This NFA accepts aa and ab nfa = NFA( states={0, 1, 2, 3, 4, 6}, input_symbols={'a', 'b'}, transitions={ 0: {'a': {1, 3}}, 1: {'b': {2}}, 2: {}, 3: {'a': {4}}, 4: {'': {6}}, 6: {} }, initial_state=0, final_states={2, 4, 6} ) # This NFA should then accept any number of repetitions # of aa or ab concatenated together. kleene_nfa = nfa.kleene_star() self.assertEqual(kleene_nfa.accepts_input(''), True) self.assertEqual(kleene_nfa.accepts_input('a'), False) self.assertEqual(kleene_nfa.accepts_input('b'), False) self.assertEqual(kleene_nfa.accepts_input('aa'), True) self.assertEqual(kleene_nfa.accepts_input('ab'), True) self.assertEqual(kleene_nfa.accepts_input('ba'), False) self.assertEqual(kleene_nfa.accepts_input('bb'), False) self.assertEqual(kleene_nfa.accepts_input('aaa'), False) self.assertEqual(kleene_nfa.accepts_input('aba'), False) self.assertEqual(kleene_nfa.accepts_input('abaa'), True) self.assertEqual(kleene_nfa.accepts_input('abba'), False) self.assertEqual(kleene_nfa.accepts_input('aaabababaaaaa'), False) self.assertEqual(kleene_nfa.accepts_input('aaabababaaaaab'), True) self.assertEqual(kleene_nfa.accepts_input('aaabababaaaaba'), False)
def __init__( self, nfa: NFA = None, *, states: set = None, input_symbols: set = None, transitions: dict = None, initial_state: str = None, final_states: set = None, ): if nfa: self.nfa = nfa.copy() else: if not states: states = {*transitions.keys()} if not input_symbols: input_symbols = set() for v in transitions.values(): symbols = [*v.keys()] for symbol in symbols: if symbol != "": input_symbols.add(symbol) self.nfa = NFA( states=states.copy(), input_symbols=input_symbols.copy(), transitions=transitions.deepcopy(), initial_state=initial_state, final_states=final_states.copy(), ) self.nfa.validate()
def test_non_str_states(self): """should handle non-string state names""" nfa = NFA( states={0}, input_symbols={0}, transitions={0: {}}, initial_state=0, final_states=set()) # We don't care what the output is, just as long as no exception is # raised nose.assert_not_equal(nfa.accepts_input(''), None)
def validar(sets, tipo): if tipo == False: aux = list(sets[2].values()) for i in range(len(sets[0])): if '' in aux[i].values() or not sets[4]: return False automata = DFA(states=sets[0], input_symbols=sets[1], transitions=sets[2], initial_state=sets[3], final_states=sets[4]) else: if sets[4]: automata = NFA(states=sets[0], input_symbols=sets[1], transitions=sets[2], initial_state=sets[3], final_states=sets[4]) else: return False if automata.validate(): del automata return True else: del automata return False
def complemento(automata, tipo): #intercambiar estados finales por estados if tipo == False: fin = [] final = automata.final_states estados = automata.states for i in estados: for l in final: if i != l: fin.append(i) finales = set(fin) automata = DFA(states=automata.states, input_symbols=automata.input_symbols, transitions=automata.transitions, initial_state=automata.initial_state, final_states=finales) return automata, tipo else: ADF = NFA.from_dfa(automata) complemento(ADF, False)
def test_init_nfa_more_complex(self): """Should convert to a DFA a more complex NFA.""" nfa = NFA( states={'q0', 'q1', 'q2'}, input_symbols={'0', '1'}, transitions={ 'q0': {'0': {'q0', 'q1'}, '1': {'q0'}}, 'q1': {'0': {'q1'}, '1': {'q2'}}, 'q2': {'0': {'q2'}, '1': {'q1'}} }, initial_state='q0', final_states={'q2'} ) dfa = DFA.from_nfa(nfa) nose.assert_equal(dfa.states, { '{q0}', '{q0,q1}', '{q0,q2}', '{q0,q1,q2}' }) nose.assert_equal(dfa.input_symbols, {'0', '1'}) nose.assert_equal(dfa.transitions, { '{q0}': {'1': '{q0}', '0': '{q0,q1}'}, '{q0,q1}': {'1': '{q0,q2}', '0': '{q0,q1}'}, '{q0,q2}': {'1': '{q0,q1}', '0': '{q0,q1,q2}'}, '{q0,q1,q2}': {'1': '{q0,q1,q2}', '0': '{q0,q1,q2}'} }) nose.assert_equal(dfa.initial_state, '{q0}') nose.assert_equal(dfa.final_states, {'{q0,q1,q2}', '{q0,q2}'})
def parseFA(fileJFLAP, prefix): # create tree object automataTree = ET.parse(fileJFLAP) # parse states parsedStates = parseStates(automataTree, prefix) # parse alphabet parsedAlphabet = parseAlphabet(automataTree) # parse transitions parsedTransitions = parseTransitions(automataTree, parsedStates, prefix) # parse initial state parsedInitial = parseInitialState(automataTree, prefix) # parse final states parsedFinals = parseFinalStates(automataTree, prefix) # build NFA nfa = NFA( states = parsedStates, input_symbols = parsedAlphabet, transitions = parsedTransitions, initial_state = parsedInitial, final_states = parsedFinals ) return nfa
def parse_json(json_string, is_deterministic): fsm = json.loads(json_string) try: states, final_states, node_map = get_states(fsm) input_symbols = get_alphabet(fsm, is_deterministic) if is_deterministic: initial_state, transitions = \ get_DFA_transitions(fsm, states, node_map, input_symbols) else: initial_state, transitions = \ get_NFA_transitions(fsm, states, node_map, input_symbols) except Exception as e: return True, str(e) if is_deterministic: fsm = DFA(states=states, input_symbols=input_symbols, transitions=transitions, initial_state=initial_state, final_states=final_states) else: fsm = NFA(states=states, input_symbols=input_symbols, transitions=transitions, initial_state=initial_state, final_states=final_states) return False, fsm
def main(): nfa = NFA( # this code builds the weakly divisible by 7 NFA states={'start_state', 'q0', 'q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q0prime', 'q1prime', 'q2prime', 'q3prime', 'q4prime', 'q5prime', 'q6prime', 'fail_state'}, input_symbols={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}, transitions={ 'start_state': {'0': {'fail_state'}, '1': {'q1', 'q0prime'}, '2': {'q2', 'q0prime'}, '3': {'q3', 'q0prime'}, '4': {'q4', 'q0prime'}, '5': {'q5', 'q0prime'}, '6': {'q6', 'q0prime'}, '7': {'q0', 'q0prime'}, '8': {'q1', 'q0prime'}, '9': {'q2', 'q0prime'}}, 'fail_state': {'0': {'fail_state'}, '1': {'fail_state'}, '2': {'fail_state'}, '3': {'fail_state'}, '4': {'fail_state'}, '5': {'fail_state'}, '6': {'fail_state'}, '7': {'fail_state'}, '8': {'fail_state'}, '9': {'fail_state'}}, 'q0': {'0': {'q0', 'q0prime'}, '1': {'q1', 'q0prime'}, '2': {'q2', 'q0prime'}, '3': {'q3', 'q0prime'}, '4': {'q4', 'q0prime'}, '5': {'q5', 'q0prime'}, '6': {'q6', 'q0prime'}, '7': {'q0', 'q0prime'}, '8': {'q1', 'q0prime'}, '9': {'q2', 'q0prime'}}, 'q1': {'0': {'q3', 'q1prime'}, '1': {'q4', 'q1prime'}, '2': {'q5', 'q1prime'}, '3': {'q6', 'q1prime'}, '4': {'q0', 'q1prime'}, '5': {'q1', 'q1prime'}, '6': {'q2', 'q1prime'}, '7': {'q3', 'q1prime'}, '8': {'q4', 'q1prime'}, '9': {'q5', 'q1prime'}, '': {'q1', 'q1prime'}}, 'q2': {'0': {'q6', 'q2prime'}, '1': {'q0', 'q2prime'}, '2': {'q1', 'q2prime'}, '3': {'q2', 'q2prime'}, '4': {'q3', 'q2prime'}, '5': {'q4', 'q2prime'}, '6': {'q5', 'q2prime'}, '7': {'q6', 'q2prime'}, '8': {'q0', 'q2prime'}, '9': {'q1', 'q2prime'}, '': {'q2', 'q2prime'}}, 'q3': {'0': {'q2', 'q3prime'}, '1': {'q3', 'q3prime'}, '2': {'q4', 'q3prime'}, '3': {'q5', 'q3prime'}, '4': {'q6', 'q3prime'}, '5': {'q0', 'q3prime'}, '6': {'q1', 'q3prime'}, '7': {'q2', 'q3prime'}, '8': {'q3', 'q3prime'}, '9': {'q4', 'q3prime'}, '': {'q3'}}, 'q4': {'0': {'q5', 'q4prime'}, '1': {'q6', 'q4prime'}, '2': {'q0', 'q4prime'}, '3': {'q1', 'q4prime'}, '4': {'q2', 'q4prime'}, '5': {'q3', 'q4prime'}, '6': {'q4', 'q4prime'}, '7': {'q5', 'q4prime'}, '8': {'q6', 'q4prime'}, '9': {'q0', 'q4prime'}, '': {'q4'}}, 'q5': {'0': {'q1', 'q5prime'}, '1': {'q2', 'q5prime'}, '2': {'q3', 'q5prime'}, '3': {'q4', 'q5prime'}, '4': {'q5', 'q5prime'}, '5': {'q6', 'q5prime'}, '6': {'q0', 'q5prime'}, '7': {'q1', 'q5prime'}, '8': {'q2', 'q5prime'}, '9': {'q3', 'q5prime'}, '': {'q5'}}, 'q6': {'0': {'q4', 'q6prime'}, '1': {'q5', 'q6prime'}, '2': {'q6', 'q6prime'}, '3': {'q0', 'q6prime'}, '4': {'q1', 'q6prime'}, '5': {'q2', 'q6prime'}, '6': {'q3', 'q6prime'}, '7': {'q4', 'q6prime'}, '8': {'q5', 'q6prime'}, '9': {'q6', 'q6prime'}, '': {'q6'}}, 'q0prime': {'0': {'q0prime'}, '1': {'q1prime'}, '2': {'q2prime'}, '3': {'q3prime'}, '4': {'q4prime'}, '5': {'q5prime'}, '6': {'q6prime'}, '7': {'q0prime'}, '8': {'q1prime'}, '9': {'q2prime'}}, 'q1prime': {'0': {'q3prime'}, '1': {'q4prime'}, '2': {'q5prime'}, '3': {'q6prime'}, '4': {'q0prime'}, '5': {'q1prime'}, '6': {'q2prime'}, '7': {'q3prime'}, '8': {'q4prime'}, '9': {'q5prime'}}, 'q2prime': {'0': {'q6prime'}, '1': {'q0prime'}, '2': {'q1prime'}, '3': {'q2prime'}, '4': {'q3prime'}, '5': {'q4prime'}, '6': {'q5prime'}, '7': {'q6prime'}, '8': {'q0prime'}, '9': {'q1prime'}}, 'q3prime': {'0': {'q2prime'}, '1': {'q3prime'}, '2': {'q4prime'}, '3': {'q5prime'}, '4': {'q6prime'}, '5': {'q0prime'}, '6': {'q1prime'}, '7': {'q2prime'}, '8': {'q3prime'}, '9': {'q4prime'}}, 'q4prime': {'0': {'q5prime'}, '1': {'q6prime'}, '2': {'q0prime'}, '3': {'q1prime'}, '4': {'q2prime'}, '5': {'q3prime'}, '6': {'q4prime'}, '7': {'q5prime'}, '8': {'q6prime'}, '9': {'q0prime'}}, 'q5prime': {'0': {'q1prime'}, '1': {'q2prime'}, '2': {'q3prime'}, '3': {'q4prime'}, '4': {'q5prime'}, '5': {'q6prime'}, '6': {'q0prime'}, '7': {'q1prime'}, '8': {'q2prime'}, '9': {'q3prime'}}, 'q6prime': {'0': {'q4prime'}, '1': {'q5prime'}, '2': {'q6prime'}, '3': {'q0prime'}, '4': {'q1prime'}, '5': {'q2prime'}, '6': {'q3prime'}, '7': {'q4prime'}, '8': {'q5prime'}, '9': {'q6prime'}} }, initial_state='start_state', final_states={'q0', 'q0prime'} ) str_length = int(input("Enter an integer for string length: ")) dfa = DFA.from_nfa(nfa) # creates a DFA from the above built NFA num_strings = count(str_length, dfa) print("The number of strings of length", str_length, "accepted by the DFA is", num_strings)
def test_cyclic_lambda_transitions(self): """Should traverse NFA containing cyclic lambda transitions.""" # NFA which matches zero or more occurrences of 'a' nfa = NFA( states={'q0', 'q1', 'q2', 'q3'}, input_symbols={'a'}, transitions={ 'q0': {'': {'q1', 'q3'}}, 'q1': {'a': {'q2'}}, 'q2': {'': {'q3'}}, 'q3': {'': {'q0'}} }, initial_state='q0', final_states={'q3'} ) nose.assert_equal(nfa.validate_input(''), {'q0', 'q1', 'q3'}) nose.assert_equal(nfa.validate_input('a'), {'q0', 'q1', 'q2', 'q3'})
def test_cyclic_lambda_transitions(self): """Should traverse NFA containing cyclic lambda transitions.""" # NFA which matches zero or more occurrences of 'a' nfa = NFA( states={'q0', 'q1', 'q2', 'q3'}, input_symbols={'a'}, transitions={ 'q0': {'': {'q1', 'q3'}}, 'q1': {'a': {'q2'}}, 'q2': {'': {'q3'}}, 'q3': {'': {'q0'}} }, initial_state='q0', final_states={'q3'} ) nose.assert_equal(nfa.read_input(''), {'q0', 'q1', 'q3'}) nose.assert_equal(nfa.read_input('a'), {'q0', 'q1', 'q2', 'q3'})
def test_init_nfa_missing_formal_params(self): """Should raise an error if formal NFA parameters are missing.""" with nose.assert_raises(TypeError): NFA( states={'q0', 'q1'}, input_symbols={'0', '1'}, initial_state='q0', final_states={'q1'} )
def markovNFA(pattern): st = getStates(pattern) nfa = NFA(states=st, input_symbols={'H', 'T'}, transitions=getTransitions(pattern), initial_state='phi', final_states={str(len(pattern))}) return nfa
def union(automata1, tipo1, automata2, tipo2): # Crear un estado inicial y juntar 2 automatas simbolos = [] for i in automata1.input_symbols: simbolos.append(i) for a in automata2.input_symbols: simbolos.append(a) simbolos.append('') estados = [] for i in automata1.states: estados.append(i) for a in automata2.states: estados.append(a) estados.append('inicio') final = [] for i in automata1.final_states: final.append(i) for a in automata2.final_states: final.append(a) dic1 = automata1.transitions.copy() dic2 = automata2.transitions.copy() dic1.update(dic2) if tipo1 == tipo2: # acepta 2 afnd if tipo1: dic1['inicio'] = { '': {automata1.initial_state, automata2.initial_state} } automata = NFA(states=set(estados), input_symbols=set(simbolos), transitions=dic1, initial_state='inicio', final_states=set(final)) return automata, tipo1 # Formato dfa: 'q0': {'0': 'q0', '1': 'q1'}, # Formato nfa: 'q1': {'0': {'q1'}, '1': {'q2'}}, else: automata2, tipo2 = AFDtoAFND(automata2, tipo2) automata1, tipo1 = AFDtoAFND(automata1, tipo1) return union(automata1, tipo1, automata2, tipo2) else: if tipo1: automata2, tipo2 = AFDtoAFND(automata2, tipo2) return union(automata1, tipo1, automata2, tipo2) if tipo2: automata1, tipo1 = AFDtoAFND(automata1, tipo1) return union(automata1, tipo1, automata2, tipo2)
def test_init_dfa(self): """Should convert DFA to NFA if passed into NFA constructor.""" nfa = NFA.from_dfa(self.dfa) nose.assert_equal(nfa.states, {'q0', 'q1', 'q2'}) nose.assert_equal(nfa.input_symbols, {'0', '1'}) nose.assert_equal(nfa.transitions, { 'q0': {'0': {'q0'}, '1': {'q1'}}, 'q1': {'0': {'q0'}, '1': {'q2'}}, 'q2': {'0': {'q2'}, '1': {'q1'}} }) nose.assert_equal(nfa.initial_state, 'q0')
def converter_nfa_dfa(estados, alfabeto, funcao_transicao, est_inicial, est_finais): nfa = NFA(states=set(estados), input_symbols=set(alfabeto), transitions=funcao_transicao, initial_state=est_inicial, final_states=set(est_finais)) dfa = DFA(nfa) return dfa
def test_concatenate(self): nfa_a = NFA( states={'q1', 'q2', 'q3', 'q4'}, input_symbols={'0', '1'}, transitions={ 'q1': {'0': {'q1'}, '1': {'q1', 'q2'}}, 'q2': {'': {'q2'}, '0': {'q2'}}, 'q3': {'1': {'q4'}}, 'q4': {'0': {'q4'}, '1': {'q4'}} }, initial_state='q1', final_states={'q2', 'q4'} ) nfa_b = NFA( states={'r1', 'r2', 'r3'}, input_symbols={'0', '1'}, transitions={ 'r1': {'': {'r3'}, '1': {'r2'}}, 'r2': {'0': {'r2', 'r3'}, '1': {'r3'}}, 'r3': {'0': {'r1'}} }, initial_state='r1', final_states={'r1'} ) concat_nfa = nfa_a + nfa_b self.assertEqual(concat_nfa.accepts_input(''), False) self.assertEqual(concat_nfa.accepts_input('0'), False) self.assertEqual(concat_nfa.accepts_input('1'), True) self.assertEqual(concat_nfa.accepts_input('00'), False) self.assertEqual(concat_nfa.accepts_input('01'), True) self.assertEqual(concat_nfa.accepts_input('10'), True) self.assertEqual(concat_nfa.accepts_input('11'), True) self.assertEqual(concat_nfa.accepts_input('101'), True) self.assertEqual(concat_nfa.accepts_input('101100'), True) self.assertEqual(concat_nfa.accepts_input('1010'), True)
def test_operations_other_type(self): """Should raise NotImplementedError for concatenate.""" nfa = NFA( states={'q1', 'q2', 'q3', 'q4'}, input_symbols={'0', '1'}, transitions={'q1': {'0': {'q1'}, '1': {'q1', 'q2'}}, 'q2': {'': {'q2'}, '0': {'q2'}}, 'q3': {'1': {'q4'}}, 'q4': {'0': {'q4'}, '1': {'q4'}}}, initial_state='q1', final_states={'q2', 'q4'}) other = 42 with self.assertRaises(NotImplementedError): nfa + other
def concatenacion(automata1, tipo1, automata2, tipo2): # entran 2 NFA y no se saca la chucha :) simbolos = [] #Saca Los simbolos de el automata 1 y 2 for i in automata1.input_symbols: simbolos.append(i) for a in automata2.input_symbols: simbolos.append(a) simbolos.append('') sim = set(simbolos) estados = [] #Saca los estados de los automatas 1 y 2 for i in automata1.states: estados.append(i) for a in automata2.states: estados.append(a) esta2 = set(estados) dic1 = automata1.transitions.copy() dic2 = automata2.transitions.copy() dic1.update(dic2) if tipo1 == tipo2: if tipo1: dic1[str(automata1.final_states)[2:4]][''] = { str(automata2.initial_state) } automata = NFA(states=esta2, input_symbols=sim, transitions=dic1, initial_state=automata1.initial_state, final_states=set(automata2.final_states)) return automata, tipo1 else: automata1, tipo1 = AFDtoAFND(automata1, tipo1) automata2, tipo2 = AFDtoAFND(automata2, tipo2) return concatenacion(automata1, tipo1, automata2, tipo2) else: if tipo1: automata2, tipo2 = AFDtoAFND(automata2, tipo2) return concatenacion(automata1, tipo1, automata2, tipo2) if tipo2: automata1, tipo1 = AFDtoAFND(automata1, tipo1) return concatenacion(automata1, tipo1, automata2, tipo2)
def test_nfa_to_dfa_with_lambda_transitions(self): """ Test NFA->DFA when initial state has lambda transitions """ nfa = NFA( states={'q0', 'q1', 'q2'}, input_symbols={'a', 'b'}, transitions={ 'q0': {'': {'q2'}}, 'q1': {'a': {'q1'}}, 'q2': {'a': {'q1'}} }, initial_state='q0', final_states={'q1'} ) dfa = DFA.from_nfa(nfa) # returns an equivalent DFA nose.assert_equal(dfa.read_input('a'), '{q1}')
def crear(sets, tipo): if tipo == False: automata = DFA(states=sets[0], input_symbols=sets[1], transitions=sets[2], initial_state=sets[3], final_states=sets[4]) else: automata = NFA(states=sets[0], input_symbols=sets[1], transitions=sets[2], initial_state=sets[3], final_states=sets[4]) return automata
def create_nfa(size, alphabet={}): states = set() transitions = {} for i in range(size): states.add(str(i)) transitions[str(i)] = {} for symbol in alphabet: transitions[str(i)][symbol] = set() return NFA(states=states, input_symbols=alphabet, transitions=transitions, initial_state="0", final_states=set())
def test_reverse(self): nfa = NFA( states={0, 1, 2, 4}, input_symbols={'a', 'b'}, transitions={ 0: {'a': {1}}, 1: {'a': {2}, 'b': {1, 2}}, 2: {}, 3: {'a': {2}, 'b': {2}} }, initial_state=0, final_states={2} ) reverse_nfa = reversed(nfa) self.assertEqual(reverse_nfa.accepts_input('a'), False) self.assertEqual(reverse_nfa.accepts_input('ab'), False) self.assertEqual(reverse_nfa.accepts_input('ba'), True) self.assertEqual(reverse_nfa.accepts_input('bba'), True) self.assertEqual(reverse_nfa.accepts_input('bbba'), True)
def setUp(self): """Reset test automata before every test function.""" # DFA which matches all binary strings ending in an odd number of '1's self.dfa = DFA(states={'q0', 'q1', 'q2'}, input_symbols={'0', '1'}, transitions={ 'q0': { '0': 'q0', '1': 'q1' }, 'q1': { '0': 'q0', '1': 'q2' }, 'q2': { '0': 'q2', '1': 'q1' } }, initial_state='q0', final_states={'q1'}) # NFA which matches strings beginning with 'a', ending with 'a', and # containing no consecutive 'b's self.nfa = NFA(states={'q0', 'q1', 'q2'}, input_symbols={'a', 'b'}, transitions={ 'q0': { 'a': {'q1'} }, 'q1': { 'a': {'q1'}, '': {'q2'} }, 'q2': { 'b': {'q0'} } }, initial_state='q0', final_states={'q1'})
def nfa_to_dfa(): json = request.get_json() states = json['states'] alphabet = json['alphabet'] initial = json['initial'] mapping = json['transitionMap'] finals = json['finals'] nfa = NFA( states=set(states), input_symbols=set(alphabet), initial_state=initial, transitions=mapping, final_states=set(finals) ) dfa = DFA(nfa) return jsonify( { "alphabet": list(dfa.input_symbols), "states": list(dfa.states), "initial": dfa.initial_state, "finals": list(dfa.final_states), "transitionMap": dfa.transitions } )
def test_init_validation(self, validate): """Should validate NFA when initialized.""" NFA.copy(self.nfa) validate.assert_called_once_with()
def AFDtoAFND(automata): nfa = NFA.from_dfa(automata) return nfa
class VisualNFA: """A wrapper for an automata-lib non-deterministic finite automaton.""" def __init__( self, nfa: NFA = None, *, states: set = None, input_symbols: set = None, transitions: dict = None, initial_state: str = None, final_states: set = None, ): if nfa: self.nfa = nfa.copy() else: if not states: states = {*transitions.keys()} if not input_symbols: input_symbols = set() for v in transitions.values(): symbols = [*v.keys()] for symbol in symbols: if symbol != "": input_symbols.add(symbol) self.nfa = NFA( states=states.copy(), input_symbols=input_symbols.copy(), transitions=transitions.deepcopy(), initial_state=initial_state, final_states=final_states.copy(), ) self.nfa.validate() # ------------------------------------------------------------------------- # Mimic behavior of automata-lib NFA. @property def states(self) -> set: """Pass on .states from the NFA""" return self.nfa.states @states.setter def states(self, states: set): """Set .states on the NFA""" self.nfa.states = states @property def input_symbols(self) -> set: """Pass on .input_symbols from the NFA""" return self.nfa.input_symbols @input_symbols.setter def input_symbols(self, input_symbols: set): """Set .input_symbols on the NFA""" self.nfa.input_symbols = input_symbols @property def transitions(self) -> dict: """Pass on .transitions from the NFA""" return self.nfa.transitions @transitions.setter def transitions(self, transitions: dict): """Set .transitions on the NFA""" self.nfa.transitions = transitions @property def initial_state(self) -> str: """Pass on .initial_state from the NFA""" return self.nfa.initial_state @initial_state.setter def initial_state(self, initial_state: str): """Set .initial_state on the NFA""" self.nfa.initial_state = initial_state @property def final_states(self) -> set: """Pass on .final_states from the NFA""" return self.nfa.final_states @final_states.setter def final_states(self, final_states: set): """Set .final_states on the NFA""" self.nfa.final_states = final_states def copy(self): """Create a deep copy of the automaton.""" return self.__class__(**vars(self)) def validate(self) -> bool: """Return True if this NFA is internally consistent.""" return self.nfa.validate() def accepts_input(self, input_str: str) -> bool: """Return True if this automaton accepts the given input.""" return self.nfa.accepts_input(input_str=input_str) def read_input(self, input_str: str) -> set: """ Check if the given string is accepted by this automaton. Return the automaton's final configuration if this string is valid. """ return self.nfa.read_input(input_str=input_str) def read_input_stepwise(self, input_str: str) -> Generator: """ Check if the given string is accepted by this automaton. Return the automaton's final configuration if this string is valid. """ return self.nfa.read_input_stepwise(input_str=input_str) def _get_lambda_closure(self, start_state: str) -> set: """ Return the lambda closure for the given state. The lambda closure of a state q is the set containing q, along with every state that can be reached from q by following only lambda transitions. """ return self.nfa._get_lambda_closure(start_state=start_state) def _get_next_current_states(self, current_states: set, input_symbol: str) -> set: """Return the next set of current states given the current set.""" return self.nfa._get_next_current_states(current_states, input_symbol) # ------------------------------------------------------------------------- # Define new attributes and their helper methods. @property def table(self) -> DataFrame: """ Generates a transition table of the given VisualNFA. Returns: DataFrame: A transition table of the VisualNFA. """ final_states = "".join(self.nfa.final_states) transitions = self._add_lambda( all_transitions=self.nfa.transitions, input_symbols=self.nfa.input_symbols, ) table: dict = {} for state, transition in sorted(transitions.items()): if state == self.nfa.initial_state and state in final_states: state = "→*" + state elif state == self.nfa.initial_state: state = "→" + state elif state in final_states: state = "*" + state row: dict = {} for input_symbol, next_states in transition.items(): cell: list = [] for next_state in sorted(next_states): if next_state in final_states: cell.append("*" + next_state) else: cell.append(next_state) if len(cell) == 1: cell = cell.pop() else: cell = "{" + ",".join(cell) + "}" row[input_symbol] = cell table[state] = row table = pd.DataFrame.from_dict(table).fillna("∅").T table = table.reindex(sorted(table.columns), axis=1) return table @staticmethod def _add_lambda(all_transitions: dict, input_symbols: str) -> dict: """ Replacing '' key name for empty string (lambda/epsilon) transitions. Args: all_transitions (dict): The NFA's transitions with '' for lambda transitions. input_symbols (str): The NFA's input symbols/alphabet. Returns: dict: Transitions with λ for lambda transitions """ all_transitions = all_transitions.deepcopy() input_symbols = input_symbols.copy() # Replacing '' key name for empty string (lambda/epsilon) transitions. for transitions in all_transitions.values(): for state, transition in list(transitions.items()): if state == "": transitions["λ"] = transition del transitions[""] input_symbols.add("λ") return all_transitions # ------------------------------------------------------------------------- # Define new class methods and their helper methods. @property def _lambda_transition_exists(self) -> bool: """ Checks if the nfa has lambda transitions. Returns: bool: If the nfa has lambda transitions, returns True; else False. """ status = False for transitions in self.nfa.transitions.values(): if "" in transitions: return True return status @classmethod def eliminate_lambda(cls, nfa): """ Eliminates lambda transitions, and returns a new nfa. Args: nfa (VisualNFA): A VisualNFA object. Returns: VisualNFA: A VisualNFA object without lambda transitions. """ if nfa._lambda_transition_exists: nfa_lambda_eliminated = nfa.copy() for state in sorted(nfa_lambda_eliminated.transitions): # Find lambda closure for the state. closures = nfa_lambda_eliminated._get_lambda_closure(state) if nfa_lambda_eliminated.initial_state == state: if closures.difference(state).issubset( nfa_lambda_eliminated.final_states): [ nfa_lambda_eliminated.final_states.add(state) for state in closures.intersection(state) ] for input_symbol in nfa_lambda_eliminated.input_symbols: next_states = nfa.nfa._get_next_current_states( closures, input_symbol) # Check if a dead state was returned. if next_states != set(): # Update the transition after lambda move has been eliminated. nfa_lambda_eliminated.transitions[state][ input_symbol] = next_states # Delete the lambda transition. if "" in nfa_lambda_eliminated.transitions[state]: del nfa_lambda_eliminated.transitions[state][""] return nfa_lambda_eliminated else: return nfa # ------------------------------------------------------------------------- # Define new methods and their helper methods. def _pathfinder( self, input_str: str, status: bool = False, counter: int = 0, main_counter: int = 0, ) -> Union[bool, list]: # pragma: no cover. Too many possibilities. """ Searches for a appropriate path to return to input_check. Args: input_str (str): Input symbols status (bool, optional): If a path is found. Defaults to False. counter (int, optional): To keep track of recursion limit in __pathsearcher. Defaults to 0. main_counter (int, optional): To keep track of recursion limit in _pathfinder. Defaults to 0. Returns: Union[bool, list]: If a path is found, and a list of transition tuples. """ counter += 1 nfa = self.copy() recursion_limit = 50 result = self.__pathsearcher(nfa, input_str, status) if result: return status, result else: main_counter += 1 if main_counter <= recursion_limit: return self._pathfinder(input_str, status, counter, main_counter=main_counter) else: status = ( "[NO VALID PATH FOUND]\n" "Try to eliminate lambda transitions and try again.\n" "Example: nfa_lambda_removed = nfa.eliminate_lambda()") return status, [] @staticmethod def __pathsearcher(nfa, input_str: str, status: bool = False, counter: int = 0 ) -> list: # pragma: no cover. Too many possibilities. """ Searches for a appropriate path to return to _pathfinder. Args: nfa (VisualNFA): A VisualNFA object. input_str (str): Input symbols. status (bool, optional): If a path is found. Defaults to False. counter (int, optional): To keep track of recursion limit. Defaults to 0. Returns: list: a list of transition tuples. """ recursion_limit = 20000 counter += 1 current_state = {(nfa.initial_state)} path = [] for symbol in input_str: next_curr = nfa._get_next_current_states(current_state, symbol) if next_curr == set(): if not status: state = {} path.append(("".join(current_state), state, symbol)) return path else: break else: state = random.choice(list(next_curr)) path.append(("".join(current_state), state, symbol)) current_state = {(state)} # Accepted path opptained. if (status and len(input_str) == (len(path)) and path[-1][1] in nfa.final_states): return path # Rejected path opptained. elif not status and len(input_str) == (len(path)): return path # No path opptained. Try again. else: if counter <= recursion_limit: return nfa.__pathsearcher(nfa, input_str, status, counter) else: return False @staticmethod def _transition_steps( initial_state, final_states, input_str: str, transitions_taken: list, status: bool, ) -> DataFrame: # pragma: no cover. Too many possibilities. """ Generates a table of taken transitions based on the input string and it's result. Args: initial_state (str): The NFA's initial state. final_states (set): The NFA's final states. input_str (str): The input string to run on the NFA. transitions_taken (list): Transitions taken from the input string. status (bool): The result of the input string. Returns: DataFrame: Table of taken transitions based on the input string and it's result. """ current_states = transitions_taken.copy() for i, state in enumerate(current_states): if state == "" or state == {}: current_states[i] = "∅" elif state == initial_state and state in final_states: current_states[i] = "→*" + state elif state == initial_state: current_states[i] = "→" + state elif state in final_states: current_states[i] = "*" + state new_states = current_states.copy() del current_states[-1] del new_states[0] inputs = [str(x) for x in input_str] inputs = inputs[:len(current_states)] transition_steps: dict = { "Current state:": current_states, "Input symbol:": inputs, "New state:": new_states, } transition_steps = pd.DataFrame.from_dict(transition_steps) transition_steps.index += 1 transition_steps = pd.DataFrame.from_dict( transition_steps).rename_axis("Step:", axis=1) if status: transition_steps.columns = pd.MultiIndex.from_product( [["[Accepted]"], transition_steps.columns]) return transition_steps, inputs else: transition_steps.columns = pd.MultiIndex.from_product( [["[Rejected]"], transition_steps.columns]) return transition_steps, inputs @staticmethod def _transitions_pairs( all_transitions: dict, ) -> list: # pragma: no cover. Too many possibilities. """ Generates a list of all possible transitions pairs for all input symbols. Args: transition_dict (dict): NFA transitions. Returns: list: All possible transitions for all the given input symbols. """ all_transitions = all_transitions.deepcopy() transition_possibilities: list = [] for state, state_transitions in all_transitions.items(): for symbol, transitions in state_transitions.items(): if len(transitions) < 2: if transitions != "" and transitions != {}: transitions = transitions.pop() transition_possibilities.append( (state, transitions, symbol)) else: for transition in transitions: transition_possibilities.append( (state, transition, symbol)) return transition_possibilities def input_check( self, input_str: str, return_result=False ) -> Union[bool, list, DataFrame]: # pragma: no cover. Too many possibilities. """ Checks if string of input symbols results in final state. Args: input_str (str): The input string to run on the NFA. return_result (bool, optional): Returns results to the show_diagram method. Defaults to False. Raises: TypeError: To let the user know a string has to be entered. Returns: Union[bool, list, list]: If the last state is the final state, transition pairs, and steps taken. """ if not isinstance(input_str, str): raise TypeError(f"input_str should be a string. " f"{input_str} is {type(input_str)}, not a string.") # Check if input string is accepted. status: bool = self.nfa.accepts_input(input_str=input_str) status, taken_transitions_pairs = self._pathfinder(input_str=input_str, status=status) if not isinstance(status, bool): if return_result: return status, [], DataFrame, input_str else: return status current_states = self.initial_state transitions_taken = [current_states] for transition in range(len(taken_transitions_pairs)): transitions_taken.append(taken_transitions_pairs[transition][1]) taken_steps, inputs = self._transition_steps( initial_state=self.nfa.initial_state, final_states=self.final_states, input_str=input_str, transitions_taken=transitions_taken, status=status, ) if return_result: return status, taken_transitions_pairs, taken_steps, inputs else: return taken_steps def show_diagram( self, input_str: str = None, filename: str = None, format_type: str = "png", path: str = None, *, view=False, cleanup: bool = True, horizontal: bool = True, reverse_orientation: bool = False, fig_size: tuple = (8, 8), font_size: float = 14.0, arrow_size: float = 0.85, state_seperation: float = 0.5, ) -> Digraph: # pragma: no cover. Too many possibilities. """ Generates the graph associated with the given NFA. Args: nfa (NFA): Deterministic Finite Automata to graph. input_str (str, optional): String list of input symbols. Defaults to None. filename (str, optional): Name of output file. Defaults to None. format_type (str, optional): File format [svg/png/...]. Defaults to "png". path (str, optional): Folder path for output file. Defaults to None. view (bool, optional): Storing and displaying the graph as a pdf. Defaults to False. cleanup (bool, optional): Garbage collection. Defaults to True. horizontal (bool, optional): Direction of node layout. Defaults to True. reverse_orientation (bool, optional): Reverse direction of node layout. Defaults to False. fig_size (tuple, optional): Figure size. Defaults to (8, 8). font_size (float, optional): Font size. Defaults to 14.0. arrow_size (float, optional): Arrow head size. Defaults to 0.85. state_seperation (float, optional): Node distance. Defaults to 0.5. Returns: Digraph: The graph in dot format. """ # Converting to graphviz preferred input type, # keeping the conventional input styles; i.e fig_size(8,8) fig_size = ", ".join(map(str, fig_size)) font_size = str(font_size) arrow_size = str(arrow_size) state_seperation = str(state_seperation) # Defining the graph. graph = Digraph(strict=False) graph.attr( size=fig_size, ranksep=state_seperation, ) if horizontal: graph.attr(rankdir="LR") if reverse_orientation: if horizontal: graph.attr(rankdir="RL") else: graph.attr(rankdir="BT") # Defining arrow to indicate the initial state. graph.node("Initial", label="", shape="point", fontsize=font_size) # Defining all states. for state in sorted(self.nfa.states): if (state in self.nfa.initial_state and state in self.nfa.final_states): graph.node(state, shape="doublecircle", fontsize=font_size) elif state in self.nfa.initial_state: graph.node(state, shape="circle", fontsize=font_size) elif state in self.nfa.final_states: graph.node(state, shape="doublecircle", fontsize=font_size) else: graph.node(state, shape="circle", fontsize=font_size) # Point initial arrow to the initial state. graph.edge("Initial", self.nfa.initial_state, arrowsize=arrow_size) # Define all tansitions in the finite state machine. all_transitions_pairs = self._transitions_pairs(self.nfa.transitions) # Replacing '' key name for empty string (lambda/epsilon) transitions. for i, pair in enumerate(all_transitions_pairs): if pair[2] == "": all_transitions_pairs[i] = (pair[0], pair[1], "λ") if input_str is None: for pair in all_transitions_pairs: graph.edge( pair[0], pair[1], label=" {} ".format(pair[2]), arrowsize=arrow_size, fontsize=font_size, ) status = None else: ( status, taken_transitions_pairs, taken_steps, inputs, ) = self.input_check(input_str=input_str, return_result=True) if not isinstance(status, bool): print(status) return remaining_transitions_pairs = [ x for x in all_transitions_pairs if x not in taken_transitions_pairs ] # Define color palette for transitions if status: start_color = hex_to_rgb_color("#FFFF00") end_color = hex_to_rgb_color("#00FF00") else: start_color = hex_to_rgb_color("#FFFF00") end_color = hex_to_rgb_color("#FF0000") number_of_colors = len(inputs) palette = create_palette(start_color, end_color, number_of_colors, sRGBColor) color_gen = list_cycler(palette) # Define all tansitions in the finite state machine with traversal. counter = 0 for i, pair in enumerate(taken_transitions_pairs): dead_state = "\u00D8" edge_color = next(color_gen) counter += 1 if pair[1] != {}: graph.edge( pair[0], pair[1], label=" [{}]\n{} ".format(counter, pair[2]), arrowsize=arrow_size, fontsize=font_size, color=edge_color, penwidth="2.5", ) else: graph.node(dead_state, shape="circle", fontsize=font_size) graph.edge( pair[0], dead_state, label=" [{}]\n{} ".format(counter, inputs[-1]), arrowsize=arrow_size, fontsize=font_size, color=edge_color, penwidth="2.5", ) for pair in remaining_transitions_pairs: graph.edge( pair[0], pair[1], label=" {} ".format(pair[2]), arrowsize=arrow_size, fontsize=font_size, ) # Write diagram to file. PNG, SVG, etc. if filename: graph.render( filename=filename, format=format_type, directory=path, cleanup=cleanup, ) if view: graph.render(view=True) if input_str: display(taken_steps) return graph else: return graph
def afn_AFD(idA, conjunto, bandera): if idA in afn_api.keys() and idA not in afn_convertidos: afn = afn_api[idA].copy() else: afn = conjunto.buscaAfn(idA) edosId = set() edosfinales = set() edosinicial = set() ##Obtener transiciones dictrans = {} alfabeto = set() estadoinicial = "" for i in afn.edosAFN: # print(str(i.identificador)) if (i.edoInicial == True): edosinicial.add(str(i.identificador)) estadoinicial = str(i.identificador) if (len(edosinicial) > 1): try: os.system("cls") except: os.system("clear") print("ERROR, HAY MAS DE UN ESTADO INICIAL") print("ESTADOS INICIALES: " + str(edosinicial)) break if (i.edoFinal == True): edosfinales.add(str(i.identificador)) agregarTokenEstado(str(i.identificador), str(i.token)) ##agregardiccionario('',i.identificador) edosId.add(str(i.identificador)) try: for j in i.transiciones: var1 = str(j.simbolo) var2 = str(j.simbolo2) var3 = str(j.edoDestino.identificador) elements_transiciones = elementos_transiciones(var1, var2) for letra in elements_transiciones: agregardiccionario(letra, var3) if letra not in alfabeto: if letra != '': alfabeto.add(letra) dictrans[str(i.identificador)] = devolverdiccionario() except: auxtran = i.transiciones if auxtran == None: agregardiccionario('', str(i.identificador)) dictrans[str(i.identificador)] = devolverdiccionario() else: elements_transiciones = elementos_transiciones( str(auxtran.simbolo), str(auxtran.simbolo2)) for letra in elements_transiciones: agregardiccionario( letra, str(auxtran.edoDestino.identificador)) if letra not in alfabeto: if letra != '': alfabeto.add(letra) dictrans[str(i.identificador)] = devolverdiccionario() afn = NFA(states=edosId, input_symbols=alfabeto, transitions=dictrans, initial_state=estadoinicial, final_states=edosfinales) afn_api[idA] = afn afd = DFA.from_nfa(afn) transicionesafd = afd.transitions.copy() if bandera == 1: return afn else: pass #print("¿CONVERSION CORRECTA?") #print(afd.validate()) # print(str(devolverTokens())) transicionesafd = afd.transitions.copy() diccionario_tokens = devolverTokens() a_borar = [] for clave, valor in afd.transitions.items(): if valor == '{}' or clave == '{}' or valor == None or clave == None or len( afd.transitions[clave]) == 0: try: del transicionesafd[clave] continue except: pass for j, h in valor.items(): if h == '{}' or h == None or j == '{}': a_borar.append(j) for k in a_borar: try: del transicionesafd[clave][k] except: continue a_borar.clear() '''for clave in afd.transitions.keys(): if clave == None or clave == '{}': try: del transicionesafd[clave] except: pass''' afd_api[idA] = afd archivoAFD = open("AFD.txt", "w") archivoAFD.write( "ESTADOS :" + str(afd.states).replace("'{}',", '').replace(",'{}'", '') + "\n") archivoAFD.write("SIMBOLOS DE ENTRADA :" + str(afd.input_symbols).replace("'}'}, '{'", "}'}, '{\n") + "\n") archivoAFD.write("TRANSICIONES :" + str(transicionesafd) + "\n") archivoAFD.write("ESTADO INICIAL :" + str(afd.initial_state) + "\n") archivoAFD.write("ESTADO(S) FINAL(ES) :" + str(afd.final_states) + "\n") archivoAFD.write("TOKENS (CLAVE, VALOR):" + str(diccionario_tokens)) archivoAFD.close() # VAMONOS CON RICK estados_rick = open("estados.pickle", "wb") #estados_rick = open("lexEdos.pickle", "wb") pickle.dump(afd.states, estados_rick) estados_rick.close() alfabeto_rick = open("alfabeto.pickle", "wb") #alfabeto_rick = open("lexAlfa.pickle", "wb") pickle.dump(afd.input_symbols, alfabeto_rick) alfabeto_rick.close() transiciones_rick = open("transiciones.pickle", "wb") #transiciones_rick = open("lexTransitions.pickle", "wb") pickle.dump(afd.transitions, transiciones_rick) transiciones_rick.close() edoInicial_rick = open("edosInicial.pickle", "wb") #edoInicial_rick = open("lexEdoIni.pickle", "wb") pickle.dump(afd.initial_state, edoInicial_rick) edoInicial_rick.close() edosFinales_rick = open("edosFinales.pickle", "wb") #edosFinales_rick = open("lexEdoFin.pickle", "wb") pickle.dump(afd.final_states, edosFinales_rick) edosFinales_rick.close() tokens_rick = open("token.pickle", "wb") #tokens_rick = open("lexToken.pickle", "wb") pickle.dump(diccionario_tokens, tokens_rick) tokens_rick.close()
def afn_AFD(idA, conjunto, bandera): if idA in afn_api.keys() and idA not in afn_convertidos: afn = afn_api[idA].copy() else: aux3 = copy.deepcopy(conjunto.con) for i in aux3: if i.idAFN == idA: afn = i # estados edosId = set() edosfinales = set() edosinicial = set() ##Obtener transiciones dictrans = {} alfabeto = set() estadoinicial = "" for i in afn.edosAFN: if (i.edoInicial == True): edosinicial.add(str(i.identificador)) estadoinicial = str(i.identificador) if (len(edosinicial) > 1): print("ERROR, HAY MAS DE UN ESTADO INICIAL") break if (i.edoFinal == True): edosfinales.add(str(i.identificador)) edosId.add(str(i.identificador)) try: for j in i.transiciones: var1 = str(j.simbolo) if j.simbolo == None or j.simbolo == " ": var1 = '' else: alfabeto.add(var1) var2 = str(j.edoDestino.identificador) agregardiccionario(var1, var2) dictrans[str(i.identificador)] = devolverdiccionario() except: auxtran = i.transiciones if auxtran == None: print(str(i.identificador)) agregardiccionario('', str(i.identificador)) dictrans[str(i.identificador)] = devolverdiccionario() else: if auxtran.simbolo == " ": var1 = '' else: var1 = str(auxtran.simbolo) alfabeto.add(var1) agregardiccionario(var1, str(auxtran.edoDestino.identificador)) dictrans[str(i.identificador)] = devolverdiccionario() afn = NFA( states=edosId, input_symbols=alfabeto, transitions=dictrans, initial_state=estadoinicial, final_states=edosfinales ) afn_api[idA] = afn afd = DFA.from_nfa(afn) transicionesafd = afd.transitions.copy() if bandera == 1: return afn else: pass print("¿CONVERSION CORRECTA?") print(afd.validate()) for k, i in afd.transitions.items(): for clave, valor in i.items(): if clave == '{}' or clave == None or valor == '{}' or valor == None: del transicionesafd[k] for clave in afd.transitions.keys(): if clave == None or clave == '{}': try: del transicionesafd[clave] except: pass print("TRANSICIONES AFD") print(str(transicionesafd)) afd_api[idA] = afd