def buildMinDFA(dfa, partition): ## showPartition(partition) ## print [s.name for s in dfa.listStates()] ## First make a new DFA and ensure that its start state is the same ## as that of the original DFA. For all the other states in the ## new DFA, just select a state from each of the state sets in the ## partition (expect for any dead-state state sets, which are ## ignored). newDFA = DFA() newDFA.startState = dfa.startState newDFA.alphabet = dfa.alphabet selectedStates = [] for stateSet in partition: if newDFA.startState in stateSet: selectedStates.append((newDFA.startState,stateSet)) elif stateSet != deadSS: selectedStates.append((list(stateSet)[0],stateSet)) ## Now construct new links in the new DFA. Note that we are ## modifiying states *shared* with the original DFA, so this ## action *corrupts* the original DFA. newDFA.finalStates = [] newDFA.regExprs = [] for state,stateSet in selectedStates: for i,successor in enumerate(state.successors): for targetState,targetStateSet in selectedStates: if successor[1] in targetStateSet: state.successors[i] = (successor[0],targetState) break if state in dfa.finalStates: newDFA.finalStates.append(state) newDFA.regExprs.append(dfa.regExprs[dfa.finalStates.index(state)]) newDFA.stateCount = len(selectedStates) return newDFA
def buildMinDFA(dfa, partition): ## showPartition(partition) ## print [s.name for s in dfa.listStates()] ## First make a new DFA and ensure that its start state is the same ## as that of the original DFA. For all the other states in the ## new DFA, just select a state from each of the state sets in the ## partition (expect for any dead-state state sets, which are ## ignored). newDFA = DFA() newDFA.startState = dfa.startState newDFA.alphabet = dfa.alphabet selectedStates = [] for stateSet in partition: if newDFA.startState in stateSet: selectedStates.append((newDFA.startState, stateSet)) elif stateSet != deadSS: selectedStates.append((list(stateSet)[0], stateSet)) ## Now construct new links in the new DFA. Note that we are ## modifiying states *shared* with the original DFA, so this ## action *corrupts* the original DFA. newDFA.finalStates = [] newDFA.regExprs = [] for state, stateSet in selectedStates: for i, successor in enumerate(state.successors): for targetState, targetStateSet in selectedStates: if successor[1] in targetStateSet: state.successors[i] = (successor[0], targetState) break if state in dfa.finalStates: newDFA.finalStates.append(state) newDFA.regExprs.append(dfa.regExprs[dfa.finalStates.index(state)]) newDFA.stateCount = len(selectedStates) return newDFA
def from_range(cls, alphabet: list, n_states: int, n_start_states: int, n_final_states: int): # Create a new empty list to hold generated states states = [] # Generate n states and label them sequantially, addimg them to the states list for i in range(0, n_states): states.append(State.from_range("S" + str(i), alphabet, n_states)) # Create a new empty DFA new_dfa = DFA() # Assign the alphabet to the DFA new_dfa.alphabet = alphabet # Create a new dictionary where the state name is the key and the state object is the # value, assign it to the DFA new_dfa.states = { k: v for k, v in [(state.name, state) for state in states] } # Assign n random start states, record their names in a set member variable new_dfa.assign_n_random_start_state_names(n_start_states) # Run bfs to determine which states are reachable and which are unreachable, # return the result bfs_output = new_dfa.bfs() # Assign which states are reachable and unreachable based on the output of bfs, # record their names in set member variables new_dfa.assign_reachable_unreachable_state_names(bfs_output) # After BFS, remove states that are unreachable from the states dictionary data structure new_dfa.remove_unreachable_states() # Assign n random final states, record their names in a set member variable new_dfa.assign_n_random_final_state_names(n_final_states) # Create transition table with only reachable states new_dfa.table_df = new_dfa.create_transition_table() # Check if the resultant dfa is valid (i.e. at least one final state is reachable from # any of the start states) invalid = new_dfa.check_invalid() # If for whatever reason it is invalid (shouldn't be possible), regenerate a new random # DFA if invalid: return DFAFactory.from_range(alphabet, n_states, n_start_states, n_final_states) else: return new_dfa
def from_parameters(cls, alphabet: list, states: list): # Create a new empty DFA new_dfa = DFA() # Assign the alphabet to the DFA new_dfa.alphabet = alphabet # Create a new dictionary where the state name is the key and the state object is the # value, assign it to the DFA new_dfa.states = { k: v for k, v in [(state.name, state) for state in states] } # Iterate over the states assigned to the dfa, find all states which are start states # and add them to the start_state_names set member variable new_dfa.start_state_names = new_dfa.find_start_state_names() # Run bfs to determine which states are reachable and which are unreachable, # return the result bfs_output = new_dfa.bfs() # Assign which states are reachable and unreachable based on the output of bfs, # record their names in set member variables new_dfa.assign_reachable_unreachable_state_names(bfs_output) # After BFS, remove states that are unreachable from the states dictionary data structure new_dfa.remove_unreachable_states() # Iterate over the remaining states assigned to the dfa, find all states which are final # states and add them to the final_state_names set member variable new_dfa.final_state_names = new_dfa.find_final_state_names() # Create transition table with only reachable states new_dfa.table_df = new_dfa.create_transition_table() # Check if the resultant dfa is valid (i.e. at least one final state is reachable from # any of the start states) invalid = new_dfa.check_invalid() # If the DFA is invalid, throw an error if invalid: raise ValueError("Proposed DFA is not valid") else: return new_dfa