/* METHOD TO EXECUTE ARBITRARY SET OPERATIONS ON THE LANGUAGES OF AUTOMATA * * Input: automataList: The list of deterministic automata on which the set operation is executed * boolOp: The boolean operation describing the set operation, that is to be executed * * Output: Deterministic automaton, that encodes the language obtained from applying the specified set operation on the languages of the input automata */ public static DFA <C, NTuple <State <S> > > ExecuteSetOperation <C, S>(List <DFA <C, S> > automataList, BooleanOperation boolOp) { int noAutomata = automataList.Count; //Initialize all five components (Q, Sigma, delta, q_0, F) of the resulting automaton: var Q = new HashSet <State <NTuple <State <S> > > >(); var Sigma = automataList[0].Sigma; var delta = new Dictionary <TwoTuple <State <NTuple <State <S> > >, C>, State <NTuple <State <S> > > >(); var F = new HashSet <State <NTuple <State <S> > > >(); var TupleStateDict = new Dictionary <NTuple <State <S> >, State <NTuple <State <S> > > >(); var q_0_as_array = new State <S> [noAutomata]; for (int i = 0; i < noAutomata; i++) { q_0_as_array[i] = automataList[i].q_0; } var q_0_as_ntuple = new NTuple <State <S> >(q_0_as_array); //Initialize workset with q_0. The workset contains all state (in NTuple-form) that still need to be processed var W = new HashSet <NTuple <State <S> > >(); W.Add(q_0_as_ntuple); int id = 0; var q_0 = new State <NTuple <State <S> > >(id, q_0_as_ntuple); id++; Q.Add(q_0); TupleStateDict.Add(q_0_as_ntuple, q_0); //Main loop: while (W.Count > 0) { var q_tuple = W.ElementAt(0); W.Remove(q_tuple); State <NTuple <State <S> > > q; if (!TupleStateDict.TryGetValue(q_tuple, out q)) { //TODO: Exception ?? } //If 'q_tuple' is final, add it to 'F_Tuples' bool[] q_acceptance_array = new bool[noAutomata]; for (int i = 0; i < noAutomata; i++) { q_acceptance_array[i] = automataList[i].F.Contains(q_tuple.content[i]); } if (boolOp.IsTrueForInterpretation(q_acceptance_array)) { F.Add(q); } //Determine where transitions out of 'q_tuple' need to go foreach (C a in Sigma) { var q_dash_array = new State <S> [noAutomata]; for (int i = 0; i < noAutomata; i++) { State <S> q_i_dash; var q_i_a_tuple = new TwoTuple <State <S>, C>(q_tuple.content[i], a); if (!automataList[i].delta.TryGetValue(q_i_a_tuple, out q_i_dash)) { //TODO: Throw exception. Non-total transition function! } q_dash_array[i] = q_i_dash; } var q_dash_tuple = new NTuple <State <S> >(q_dash_array); State <NTuple <State <S> > > q_dash; if (!TupleStateDict.ContainsKey(q_dash_tuple)) { W.Add(q_dash_tuple); q_dash = new State <NTuple <State <S> > >(id, q_dash_tuple); id++; Q.Add(q_dash); TupleStateDict.Add(q_dash_tuple, q_dash); } else if (!TupleStateDict.TryGetValue(q_dash_tuple, out q_dash)) { //TODO: Exception. That'd be weird. } delta.Add(new TwoTuple <State <NTuple <State <S> > >, C>(q, a), q_dash); } } return(new DFA <C, NTuple <State <S> > >(Q, Sigma, delta, q_0, F)); }
//Old version of method 'ExecuteSetOperation': public static DFA <C, List <State <S> > > ExecuteSetOperationOld <C, S>(List <DFA <C, S> > automataList, BooleanOperation boolOp) { int noAutomata = automataList.Count; //Give every state in each automaton 'Q' in 'automataList' a unique id between '0' and 'Q.Count' (included and excluded): foreach (DFA <C, S> D in automataList) { D.Enumerate(); } //Array, thats i-th component contains the number of states of 'automataList[i]': int[] automataSizes = new int[noAutomata]; for (int i = 0; i < noAutomata; i++) { automataSizes[i] = automataList[i].Q.Count; } //Stores references to all states of product-automaton, that have already been created: Array Q_reference_array = Array.CreateInstance(typeof(State <List <State <S> > >), automataSizes); //Initialize all five components (Q,Sigma,delta,q_0,F) of the resulting automaton: HashSet <State <List <State <S> > > > Q = new HashSet <State <List <State <S> > > >(); HashSet <C> Sigma = automataList[0].Sigma; Dictionary <TwoTuple <State <List <State <S> > >, C>, State <List <State <S> > > > delta = new Dictionary <TwoTuple <State <List <State <S> > >, C>, State <List <State <S> > > >(); HashSet <State <List <State <S> > > > F = new HashSet <State <List <State <S> > > >(); List <State <S> > q_0_as_list = new List <State <S> >(); foreach (DFA <C, S> D in automataList) { q_0_as_list.Add(D.q_0); } //Initialize workset with the initial state [q_0_1, q_0_2, ...]: HashSet <List <State <S> > > W = new HashSet <List <State <S> > >(); W.Add(q_0_as_list); while (W.Count > 0) { //Pick 'q = [q_1,q_2,...]' from 'W' and add it to 'Q'. //Mark in 'Q_reference_array', that 'q' has been added, by referencing it at the position determined by the id's of the states 'q_1', 'q_2', ... respectively: List <State <S> > q_list = W.ElementAt(0); W.Remove(q_list); int[] indices_q = new int[noAutomata]; for (int i = 0; i < noAutomata; i++) { indices_q[i] = q_list[i].id; } State <List <State <S> > > q; if (Q_reference_array.GetValue(indices_q) == null) { q = new State <List <State <S> > >(q_list); Q_reference_array.SetValue(q, indices_q); } else { q = (State <List <State <S> > >)Q_reference_array.GetValue(indices_q); } Q.Add(q); //Add q to F if it is accepting bool[] q_acceptance_array = new bool[noAutomata]; for (int i = 0; i < noAutomata; i++) { q_acceptance_array[i] = automataList[i].F.Contains(q_list[i]); } if (boolOp.IsTrueForInterpretation(q_acceptance_array)) { F.Add(q); } //Determine, where transitions out of 'q' need to go: foreach (C c in Sigma) { //Determine 'q_new = delta(q, c)' and its id-array ('indices'): List <State <S> > q_new_list = new List <State <S> >(); int[] indices = new int[noAutomata]; for (int i = 0; i < noAutomata; i++) { State <S> q_temp; TwoTuple <State <S>, C> tuple = new TwoTuple <State <S>, C>(q_list[i], c); if (!automataList[i].delta.TryGetValue(tuple, out q_temp)) { return(null); //TODO: throw proper exception rather than returning null } q_new_list.Add(q_temp); indices[i] = q_temp.id; } //If not yet in there, add 'q_new' to 'Q': State <List <State <S> > > q_new; if (Q_reference_array.GetValue(indices) == null) { q_new = new State <List <State <S> > >(q_new_list); Q_reference_array.SetValue(q_new, indices); W.Add(q_new_list); } else { q_new = (State <List <State <S> > >)Q_reference_array.GetValue(indices); } //Add new transition to 'delta': TwoTuple <State <List <State <S> > >, C> key = new TwoTuple <State <List <State <S> > >, C>(q, c); delta.Add(key, q_new); } } //Determine id-array of initial state: int[] indices_q_0 = new int[noAutomata]; for (int i = 0; i < noAutomata; i++) { indices_q_0[i] = automataList[i].q_0.id; } State <List <State <S> > > q_0 = (State <List <State <S> > >)Q_reference_array.GetValue(indices_q_0); //Return new DFA composed of calculated sets: return(new DFA <C, List <State <S> > >(Q, Sigma, delta, q_0, F)); }