internal FiniteAutomaton(IEnumerable <State> states, char[] alphabet, State initial, IEnumerable <State> acceptings, TransitionTable table) { this.states = states.ToArray(); ValidateAlphabet(alphabet); this.alphabet = new Alphabet(alphabet); if (!states.Contains(initial)) { throw new ArgumentException("Invalid initial state."); } this.initial = initial; var acceptingList = new List <State>(); foreach (var state in acceptings) { if (!states.Contains(state)) { throw new ArgumentException("Invalid accepting state."); } acceptingList.Add(state); } this.acceptings = acceptingList.ToArray(); var tableStates = table.GetAllStates(); foreach (var state in tableStates) { if (!states.Contains(state)) { throw new ArgumentException("Invalid table."); } } var tableChars = table.GetAllCharactersIncludingEpsilon(); foreach (var character in tableChars) { ValidateChar(character); } this.table = table; this.table.WrapUp(); }
public FiniteAutomaton(int statesCount, char[] alphabet, Transition[] transitions, int initialIndex, int[] acceptingIndexes) { ValidateAlphabet(alphabet); this.alphabet = new Alphabet(alphabet); this.states = new State[statesCount]; for (int i = 0; i < statesCount; i++) { this.states[i] = new State(); } if (ArrayHasDuplicates(acceptingIndexes)) { throw new ArgumentException("Accepting indexes cannot contain duplicates."); } int acceptingsCount = acceptingIndexes.Length; this.acceptings = new State[acceptingsCount]; for (int i = 0; i < acceptingsCount; i++) { this.acceptings[i] = StateFromIndex(acceptingIndexes[i]); } this.initial = StateFromIndex(initialIndex); if (ArrayHasDuplicates(transitions)) { throw new ArgumentException("Transitions cannot contain duplicates."); } this.table = new TransitionTable(); foreach (var info in transitions) { AddTransition(info); } this.table.WrapUp(); }
private FiniteAutomaton Minimize() { // Algorithm: Table-filling // must operate on a DFA, or else var considerations = new Queue <StatePair>(); var allPairs = new List <StatePair>(); var reachableStates = GetReachableStates().ToArray(); #if DEBUG bool duplicatedStates = reachableStates.Distinct().Count() > reachableStates.Length; Debug.Assert(!duplicatedStates); #endif foreach (var pair in GetAllPairs(reachableStates)) { allPairs.Add(pair); bool canBeMarked = CanBeConcludedDistinguishable(pair); if (canBeMarked) { pair.Mark(); } else { considerations.Enqueue(pair); } } while (considerations.Count > 0) { var thisPair = considerations.Dequeue(); foreach (char character in alphabet) { var nextPair = GetNextPair(thisPair, character); if (nextPair.State1 == nextPair.State2) { continue; } var matches = from pair in allPairs where pair == nextPair select pair; Debug.Assert(matches.Count() == 1); var match = matches.First(); if (match.IsMarked) { thisPair.Mark(); break; } else if (considerations.Contains(match)) { match.AddEquivalentPair(thisPair); } } } var minimizedToDFA = new Dictionary <State, List <State> >(); var dfaToMinimized = new Dictionary <State, State>(); foreach (var dfaState in reachableStates) { var equivalentClass = new List <State>(); equivalentClass.Add(dfaState); var minimizedState = new State(); minimizedToDFA.Add(minimizedState, equivalentClass); dfaToMinimized.Add(dfaState, minimizedState); } foreach (var pair in allPairs) { if (!pair.IsMarked) { State minimized1, minimized2; bool success1 = dfaToMinimized.TryGetValue(pair.State1, out minimized1), success2 = dfaToMinimized.TryGetValue(pair.State2, out minimized2); Debug.Assert(success1); Debug.Assert(success2); List <State> class1, class2; success1 = minimizedToDFA.TryGetValue(minimized1, out class1); success2 = minimizedToDFA.TryGetValue(minimized2, out class2); Debug.Assert(success1); Debug.Assert(success2); class1.AddRange(class2); minimizedToDFA.Remove(minimized2); dfaToMinimized[pair.State2] = minimized1; } } var newTable = new TransitionTable(); var transitions = table.GetAllTransitions(); foreach (var transition in transitions) { char character = transition.Item2; State dfaCurrent = transition.Item1, dfaNext = transition.Item3; bool isIsolated = !reachableStates.Contains(dfaCurrent); if (isIsolated) { continue; } State minimizedCurrent = dfaToMinimized[dfaCurrent], minimizedNext = dfaToMinimized[dfaNext]; bool merged = dfaCurrent != dfaNext && minimizedCurrent == minimizedNext; if (merged) { continue; } var nextStates = newTable.GetNextStates(minimizedCurrent, character); bool duplicate = nextStates.Contains(minimizedNext); if (!duplicate) { newTable.Add(minimizedCurrent, character, minimizedNext); } } var newStates = from equivalence in minimizedToDFA select equivalence.Key; var newInitial = dfaToMinimized[initial]; var newAccepting = from equivalence in minimizedToDFA where acceptings.Contains(equivalence.Value.First()) select equivalence.Key; return(new FiniteAutomaton(newStates.ToArray(), alphabet.ToArray(), newInitial, newAccepting, newTable)); }
public FiniteAutomaton ToDFA() { // Algorithm: Powerset Construction bool isAlreadyDeterministic = IsDeterministic(); if (isAlreadyDeterministic) { return(this); } List <State> dfaStates = new List <State>(), dfaAcceptings = new List <State>(); var nfaStatesComparer = new OrderIndependentStatesComparer(); var nfaToDFA = new Dictionary <IEnumerable <State>, State>(nfaStatesComparer); var dfaToNFA = new Dictionary <State, IEnumerable <State> >(); State dfaInitial = new State(); var nfaInitialClosure = table.GetInitialEpsilonClosure(initial); if (HasAcceptingState(nfaInitialClosure)) { dfaAcceptings.Add(dfaInitial); } dfaStates.Add(dfaInitial); nfaToDFA.Add(nfaInitialClosure, dfaInitial); dfaToNFA.Add(dfaInitial, nfaInitialClosure); var dfaTable = new TransitionTable(); var considerations = new Queue <State>(dfaStates); while (considerations.Count > 0) { var dfaState = considerations.Dequeue(); IEnumerable <State> correspondingNFAStates; // It is OK for this to be empty. bool success = dfaToNFA.TryGetValue(dfaState, out correspondingNFAStates); Debug.Assert(success); foreach (char character in alphabet) { var nextNFAStates = table.GetNextStates(correspondingNFAStates, character); State nextDFAState; success = nfaToDFA.TryGetValue(nextNFAStates, out nextDFAState); if (!success) { nextDFAState = new State(); if (HasAcceptingState(nextNFAStates)) { dfaAcceptings.Add(nextDFAState); } dfaStates.Add(nextDFAState); nfaToDFA.Add(nextNFAStates, nextDFAState); dfaToNFA.Add(nextDFAState, nextNFAStates); considerations.Enqueue(nextDFAState); } else { Debug.Assert(dfaStates.Contains(nextDFAState)); } dfaTable.Add(dfaState, character, nextDFAState); } } return(new FiniteAutomaton(dfaStates, alphabet.ToArray(), dfaInitial, dfaAcceptings, dfaTable)); }