def get(self, statediag, accepted=None): """ Replaces complex state IDs as generated from the product operation, into simple sequencial numbers. A dictionaty is maintained in order to map the existed IDs. Args: statediag (list): The states of the PDA accepted (list): the list of DFA accepted states Returns: list: """ count = 0 statesmap = {} newstatediag = {} for state in statediag: # Simplify state IDs if statediag[state].id not in statesmap: statesmap[statediag[state].id] = count mapped = count count = count + 1 else: mapped = statesmap[statediag[state].id] # Simplify transitions IDs transitions = {} for nextstate in statediag[state].trans: if nextstate not in statesmap: statesmap[nextstate] = count transmapped = count count = count + 1 else: transmapped = statesmap[nextstate] transitions[transmapped] = statediag[state].trans[nextstate] newstate = PDAState() newstate.id = mapped newstate.type = statediag[state].type newstate.sym = statediag[state].sym newstate.trans = transitions newstatediag[mapped] = newstate newaccepted = None if accepted is not None: newaccepted = [] for accepted_state in accepted: if (0, accepted_state) in statesmap: newaccepted.append(statesmap[(0, accepted_state)]) return newstatediag, count, newaccepted
def _generate_state(self, trans): """ Creates a new POP state (type - 2) with the same transitions. The POPed symbol is the unique number of the state. Args: trans (dict): Transition dictionary Returns: Int: The state identifier """ state = PDAState() state.id = self.nextstate() state.type = 2 state.sym = state.id state.trans = trans.copy() self.toadd.append(state) return state.id
def get(self, statediag, dfaaccepted): """ # - Remove all the POP (type - 2) transitions to state 0,non DFA accepted # for symbol @closing # - Generate the accepted transitions - Replace DFA accepted States with a push - pop symbol and two extra states Args: statediag (list): The states of the PDA dfaaccepted (list):The list of DFA accepted states Returns: list: A cleaned, smaller list of DFA states """ newstatediag = {} newstate = PDAState() newstate.id = 'AI,I' # BECAREFUL WHEN SIMPLIFYING... newstate.type = 1 newstate.sym = '@wrapping' transitions = {} transitions[(0, 0)] = [0] newstate.trans = transitions i = 0 newstatediag[i] = newstate # print 'accepted:' # print dfaaccepted for stateid in statediag: state = statediag[stateid] # print state.id if state.type == 2: for state2id in dfaaccepted: # print state.id[1] if state.id[1] == state2id: # print 'adding...' state.trans['AI,I'] = ['@wrapping'] # print state.trans break i = i + 1 newstatediag[i] = state return newstatediag
def _mkpda(self, nonterms, productions, productions_struct, terminals, splitstring=1): """ This function generates a PDA from a CNF grammar as described in: - http://www.oit.edu/faculty/sherry.yang/CST229/Lectures/7_pda.pdf - http://www.eng.utah.edu/~cs3100/lectures/l18/pda-notes.pdf If all of the grammar productions are in the Chomsky Normal Form, then follow the template for constructing a pushdown symautomata: 1. Start 2. Push S 3. Pop 4. Case: Nonterminal A: For every production rule of this form: A: BC, Push C and then Push B Args: nonterms (list): Non terminals list productions (dict): productions in the CNF form: A -> a or A -> b0b1, or S -> e productions_struct (dict): productions in the CNF form in structure form object.a for A -> a, object.b0 and object.b1 for A -> b0b1 and object.type where type is 1 for A-->a and 2 for A-->b0b1 terminals (list): All terminals splitstring (bool): If enabled an extra space is added after each symbol. Returns: PDA: The generated PDA """ pda = PDA(self.alphabet) pda.nonterminals = nonterms pda.terminals = terminals pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].sym = '@closing' pda.s[pda.n].type = 1 pda.s[pda.n].trans[1] = [0] pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 1 pda.s[pda.n].sym = nonterms[0] pda.s[pda.n].trans[2] = [0] pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 2 pda.s[pda.n].trans[0] = ['@closing'] counter = 0 i = 0 while i < len(nonterms): j = 0 while j < len(productions[nonterms[i]]): if productions_struct[counter].type == 1: # ADD AND CONNECT STATE pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n if pda.n not in pda.s[2].trans: pda.s[2].trans[pda.n] = [] pda.s[2].trans[pda.n].append(nonterms[i]) if splitstring == 0: # FILL NEW STATE READ pda.s[pda.n].type = 3 pda.s[pda.n].trans[2] = [productions_struct[counter].a] else: # THE FOLLOWIN SWITCH IS DUE TO THE REQUIREMENT OF # HAVING STRINGS SPLITTED TO SYMBOLS AND CAN INTERSECT # WITH DFA if productions_struct[counter].a not in terminals or \ len(productions_struct[counter].a) == 1: # FILL NEW STATE READ pda.s[pda.n].type = 3 pda.s[pda.n].trans[pda.n + 1] = [ productions_struct[counter].a.lower() ] pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 3 pda.s[pda.n].trans[2] = [' '] else: pda.s[pda.n].type = 3 pda.s[pda.n].trans[pda.n + 1] = \ [productions_struct[counter].a[0].lower()] k = 1 while k < len(productions_struct[counter].a) - 1: pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 3 pda.s[pda.n].trans[pda.n +1] = \ [productions_struct[counter].a[k].lower()] k = k + 1 pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 3 pda.s[pda.n].trans[pda.n + 1] = \ [productions_struct[counter].a[-1].lower()] pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n pda.s[pda.n].type = 3 pda.s[pda.n].trans[2] = [' '] else: # ADD AND CONNECT PUSH STATE pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n if pda.n not in pda.s[2].trans: pda.s[2].trans[pda.n] = [] pda.s[2].trans[pda.n].append(nonterms[i]) # FILL NEW STATE pda.s[pda.n].type = 1 pda.s[pda.n].sym = productions_struct[counter].b1 pda.s[pda.n].trans[(pda.n) + 1] = [0] # ADD AND CONNECT PUSH STATE (ALREADY CONNECTED) pda.n = pda.n + 1 pda.s[pda.n] = PDAState() pda.s[pda.n].id = pda.n # FILL NEW STATE pda.s[pda.n].type = 1 pda.s[pda.n].sym = productions_struct[counter].b0 pda.s[pda.n].trans[2] = [0] j = j + 1 counter = counter + 1 i = i + 1 return pda
def _intesect(self): """The intesection of a PDA and a DFA""" p1automaton = self.mma p2automaton = self.mmb p3automaton = PDA(self.alphabet) self._break_terms() p1counter = 0 p3counter = 0 p2states = list(p2automaton.states) print 'PDA States: ' + repr(p1automaton.n) print 'DFA States: ' + repr(len(list(p2states))) ignorechars = p1automaton.nonterminals + [0] + ['@closing'] del (ignorechars[ignorechars.index('S')]) while p1counter < p1automaton.n + 1: p1state = p1automaton.s[p1counter] p2counter = 0 while p2counter < len(list(p2states)): p2state = p2states[p2counter] tempstate = PDAState() tempstate.id = (p1state.id, p2state.stateid) tempstate.sym = p1state.sym tempstate.type = p1state.type tempstate.trans = {} found = 0 for char in self.alphabet: if char in ignorechars: continue # DFA has single destination from a state p2dest = self._delta(p2automaton, p2state, char) # PDA may have multiple destinations from a state # print p1state.trans if p2dest is not None: for potential in p1state.trans: if char in p1state.trans[potential]: found = 1 p1dest = potential if (p1dest, p2dest.stateid) not in tempstate.trans: tempstate.trans[(p1dest, p2dest.stateid)] = [] # print 'Appending A Transition to # ('+`p1dest`+','+`p2dest.stateid`+') for # input '+`char` tempstate.trans[(p1dest, p2dest.stateid)].append(char) # THEN THE NONTERMINALS + 0 3 transitions # print p1state.trans # print p1automaton.nonterminals if found == 0 and p1state.type == 3 and len(p1state.trans) > 0: assert 1==1,'Check Failed: A READ state with transitions' \ ' did not participate in the cross product' if p2dest is not None: for nonterm in p1automaton.nonterminals + \ [0] + ['@closing']: for potential in p1state.trans: if nonterm in p1state.trans[potential]: p1dest = potential if (p1dest, p2state.stateid ) not in tempstate.trans: tempstate.trans[(p1dest, p2state.stateid)] = [] # print 'Appending B Transition to # ('+`p1dest`+','+`p2state.stateid`+') for # input '+`nonterm` tempstate.trans[( p1dest, p2state.stateid)].append(nonterm) p3automaton.s[p3counter] = tempstate p3counter = p3counter + 1 p2counter = p2counter + 1 p1counter = p1counter + 1 # print 'Total States Appended '+`len(p3automaton.input_string)` p3automaton.n = p3counter - 1 p3automaton.accepted = [] for state in p2automaton.states: if state.final != TropicalWeight(float('inf')): p3automaton.accepted.append(state.stateid) return p3automaton
def _break_terms(self): counter = len(self.mma.s) for state in self.mma.s.keys(): if self.mma.s[state].type == 3: for transition in self.mma.s[state].trans.keys(): for transition in self.mma.s[state].trans.keys(): for record in self.mma.s[state].trans[transition]: if len(record) > 1: value = record i = self.mma.s[state].trans[transition].index( record) del self.mma.s[state].trans[transition][i] if len(self.mma.s[state].trans[transition] ) == 0: del self.mma.s[state].trans[transition] tempstate = PDAState() tempstate.id = counter tempstate.sym = 0 tempstate.type = 3 tempstate.trans = {} tempstate.trans[transition] = [value[-1]] self.mma.s[counter] = tempstate counter = counter + 1 for character in reversed(value[1:-1]): tempstate = PDAState() tempstate.id = counter tempstate.sym = 0 tempstate.type = 3 tempstate.trans = {} tempstate.trans[counter - 1] = [character] self.mma.s[counter] = tempstate counter = counter + 1 self.mma.s[state].trans[counter - 1] = [value[0]] self.mma.n = counter - 1
def _combine_push_rest(self): """Combining Push and Rest""" new = [] change = 0 # DEBUG # logging.debug('Combining Push and Rest') i = 0 examinetypes = self.quickresponse_types[1] for state in examinetypes: if state.type == 1: for nextstate_id in state.trans.keys(): found = 0 # if nextstate_id != state.id: if nextstate_id in self.quickresponse: examines = self.quickresponse[nextstate_id] for examine in examines: if examine.id == nextstate_id and examine.type == 3: temp = PDAState() temp.type = 1 temp.sym = state.sym temp.id = state.id for nextnextstate_id in examine.trans: # if nextnextstate_id != examine.id : for x_char in state.trans[nextstate_id]: for z_char in examine.trans[ nextnextstate_id]: if nextnextstate_id not in temp.trans: temp.trans[ nextnextstate_id] = [] if x_char != 0 and z_char != 0: temp.trans[ nextnextstate_id].append( x_char + z_char) # DEBUGprint 'transition is now # '+x_char +' + '+ z_char elif x_char != 0 and z_char == 0: temp.trans[ nextnextstate_id].append( x_char) # DEBUGprint 'transition is now # '+x_char elif x_char == 0 and z_char != 0: temp.trans[ nextnextstate_id].append( z_char) # DEBUGprint 'transition is now # '+z_char elif x_char == 0 and z_char == 0: temp.trans[ nextnextstate_id].append(0) # DEBUGprint 'transition is now # empty' else: pass found = 1 new.append(temp) if found == 1: # DEBUGprint 'Lets combine one with id # '+`state.id`+'(push) and one with id # '+`nextstate_id`+'(rest)' change = 1 del state.trans[nextstate_id] i = i + 1 if change == 0: return [] else: return new
def _combine_push_pop(self): """Combining Push and Pop""" new = [] change = 0 # DEBUG # logging.debug('Combining Push and Pop') i = 0 examinetypes = self.quickresponse_types[1] for state in examinetypes: if state.type == 1: found = 0 for nextstate_id in state.trans.keys(): # if nextstate_id != state.id: if nextstate_id in self.quickresponse: examines = self.quickresponse[nextstate_id] for examine in examines: secondfound = 0 if examine.id == nextstate_id and examine.type == 2: temp = PDAState() temp.type = 3 temp.sym = 0 temp.id = state.id if examine.sym == 0: for nextnextstate_id in examine.trans: # if nextnextstate_id != examine.id : for z_char in examine.trans[ nextnextstate_id]: if state.sym == z_char: for x_char in state.trans[ nextstate_id]: # DEBUGprint state.sym+' vs # '+z_char if nextnextstate_id not in temp.trans: temp.trans[ nextnextstate_id] = [] if x_char != 0: temp.trans[ nextnextstate_id].append( x_char) # DEBUGprint # 'transition is now # '+x_char else: temp.trans[ nextnextstate_id].append( 0) # DEBUGprint # 'transition is now # empty' secondfound = 1 elif state.sym == examine.sym: for nextnextstate_id in examine.trans: # if nextnextstate_id != examine.id : for x_char in state.trans[ nextstate_id]: for z_char in examine.trans[ nextnextstate_id]: if nextnextstate_id not in temp.trans: temp.trans[ nextnextstate_id] = [] if x_char != 0 and z_char != 0: temp.trans[ nextnextstate_id].append( x_char + z_char) # DEBUGprint 'transition is # now '+x_char +' + '+ z_char elif x_char != 0 and z_char == 0: temp.trans[ nextnextstate_id].append( x_char) # DEBUGprint 'transition is # now '+x_char elif x_char == 0 and z_char != 0: temp.trans[ nextnextstate_id].append( z_char) # DEBUGprint 'transition is # now '+z_char elif x_char == 0 and z_char == 0: temp.trans[ nextnextstate_id].append( 0) # DEBUGprint 'transition is # now empty' else: pass secondfound = 1 if secondfound == 1: new.append(temp) found = 1 if found == 1: # DEBUGprint 'Lets combine one with id # '+`state.id`+'(push) and one with id # '+`nextstate_id`+'(pop)' change = 1 # DEBUGprint 'delete '+`nextstate_id`+' from # '+`state.id` del state.trans[nextstate_id] i = i + 1 if change == 0: return [] else: return new