// Removes the states that are not on a successful path in the automaton. public static Fsa Trim(this Fsa automaton) { var transitiveClosure = automaton.Transitions .Select(t => (t.From, t.To)) .ToHashSet() .TransitiveClosure(); var reachableFromInitial = automaton.Initial .Union(transitiveClosure .Where(x => automaton.Initial.Contains(x.Item1)) .Select(x => x.Item2)); var leadingToFinal = automaton.Final .Union(transitiveClosure .Where(x => automaton.Final.Contains(x.Item2)) .Select(x => x.Item1)); var states = reachableFromInitial.Intersect(leadingToFinal).ToList(); var transitions = automaton.Transitions .Where(t => states.Contains(t.From) && states.Contains(t.To)) .Select(t => ( states.IndexOf(t.From), t.Label, states.IndexOf(t.To))); var newInitial = states.Intersect(automaton.Initial); var newFinal = states.Intersect(automaton.Final); return(new Fsa( states.Select(s => states.IndexOf(s)), newInitial.Select(s => states.IndexOf(s)), newFinal.Select(s => states.IndexOf(s)), transitions)); }
public static Fsa Concat(this Fsa first, Fsa second) { var firstFinalStates = first.Final; second = Remap(second, first.States); var secondInitialStates = second.Initial; var initialStates = first.Initial.Intersect(first.Final).Any() ? first.Initial.Union(second.Initial) : first.Initial; var transitions = first.Transitions.Union(second.Transitions).ToList(); foreach (var tr in first.Transitions.Where(t => first.Final.Contains(t.To))) { foreach (var state in second.Initial) { transitions.Add((tr.From, tr.Label, state)); } } return(new Fsa( states: first.States.Union(second.States), initialStates, second.Final, transitions)); }
// Convert to a classical Fsa where each transition label has length <= 1 public static Fsa Expand(this Fsa automaton) { var multiSymbolTransitions = automaton.Transitions.Where(t => t.Label.Length > 1); var newStates = automaton.States.ToList(); var newTransitions = automaton.Transitions.Except(multiSymbolTransitions).ToHashSet(); foreach (var tr in multiSymbolTransitions) { var wordLen = tr.Label.Length; var intermediateStates = KNewStates(wordLen - 1, newStates); var stateSeq = new[] { tr.From } .Concat(intermediateStates) .Concat(new[] { tr.To }) .ToList(); newStates.AddRange(intermediateStates); var path = Enumerable.Range(0, stateSeq.Count - 1) .Select(i => (stateSeq[i], tr.Label[i].ToString(), stateSeq[i + 1])); newTransitions.UnionWith(path); } return(new Fsa(newStates, automaton.Initial, automaton.Final, newTransitions)); }
public static Fsa Union(this Fsa first, Fsa second) { second = Remap(second, first.States); return(new Fsa( states: first.States.Concat(second.States), initial: first.Initial.Concat(second.Initial), final: first.Final.Concat(second.Final), transitions: first.Transitions.Concat(second.Transitions))); }
// Clones the finite automaton by renaming the states static Fsa Remap(this Fsa automaton, IReadOnlyCollection <int> states) { var k = states.Count; return(new Fsa( automaton.States.Select(s => s + k), automaton.Initial.Select(s => s + k), automaton.Final.Select(s => s + k), automaton.Transitions.Select(t => (t.From + k, t.Label, t.To + k)))); }
public static Fsa Optional(this Fsa automaton) { var state = new[] { NewState(automaton.States) }; return(new Fsa( automaton.States.Union(state), automaton.Initial.Union(state), automaton.Final.Union(state), automaton.Transitions)); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test void shouldFailGracefullyWhenPathCannotBeCreated() internal virtual void ShouldFailGracefullyWhenPathCannotBeCreated() { Path = new FileAnonymousInnerClass(this, TestDirectory.directory(), System.Guid.randomUUID().ToString()); IOException exception = assertThrows(typeof(IOException), () => Fsa.mkdirs(Path)); assertFalse(Fsa.fileExists(Path)); string expectedMessage = format(UNABLE_TO_CREATE_DIRECTORY_FORMAT, Path); assertThat(exception.Message, @is(expectedMessage)); }
/* Removes the epsilon transitions and preserves the automaton's language but * does not preserve the language of the individual states */ public static Fsa EpsilonFree(this Fsa automaton) { var initial = automaton.Initial.SelectMany(automaton.EpsilonClosure); var transitions = automaton.Transitions .Where(t => !string.IsNullOrEmpty(t.Label)) .SelectMany(t => automaton .EpsilonClosure(t.To) .Select(es => (t.From, t.Label, es))); return(new Fsa(automaton.States, initial, automaton.Final, transitions)); }
public static Dfsa Determinize(this Fsa automaton) { var fsa = automaton.EpsilonFree().Expand(); var subsetStates = new List <ISet <int> > { fsa.Initial.ToHashSet() }; var dfsaTransitions = new Dictionary <(int, char), int>(); var stateTransitionMap = fsa.Transitions .GroupBy(t => t.From, t => (t.Label, t.To)) .ToDictionary(g => g.Key, g => g.ToList()); for (var n = 0; n < subsetStates.Count; n++) // we break from the loop when there is no unexamined state { var symbolToStates = subsetStates[n] // take the last unexamined subset state .Where(s => stateTransitionMap.ContainsKey(s)) // keep only the items with outgoing transitions .SelectMany(s => stateTransitionMap[s]) // flatten into a set of (symbol, target) pairs .GroupBy(p => p.Label.Single(), p => p.To) // group them by symbol (fsa has only symbol transitions becase of "Expand") .ToDictionary(g => g.Key, g => g.ToHashSet()); // convert to dictionary of type <symbol, set of states> foreach (var kvp in symbolToStates) { var state = kvp.Value; // the newly formed state sets are in the Dfsa var label = kvp.Key; if (!subsetStates.Any(ss => ss.SetEquals(state))) // check if it has been added { subsetStates.Add(state); } dfsaTransitions.Add( (n, label), // n is the index of the currently examined subset state, pair.Key (symbol) is the trans. label subsetStates.FindIndex(ss => ss.SetEquals(state))); // goes to the index of the subset } } // DFA state names are the indices of the state subsets var renamedStates = Enumerable.Range(0, subsetStates.Count); // if a state subset contains a final state from the original automaton // then it is marked as final in the deterministic automaton var finalStates = renamedStates .Where(index => subsetStates[index].Intersect(fsa.Final).Any()); return(new Dfsa(renamedStates, 0, finalStates, dfsaTransitions)); }
public static Fsa Plus(this Fsa automaton) { var initial = NewState(automaton.States); var initialStates = new int[] { initial }; var newTransitions = new List <(int, string, int)>(); foreach (var state in automaton.Initial) { newTransitions.Add((initial, string.Empty, state)); } foreach (var state in automaton.Final) { newTransitions.Add((state, string.Empty, initial)); } return(new Fsa( automaton.States.Concat(initialStates), initialStates, automaton.Final, automaton.Transitions.Concat(newTransitions))); }
public static Fsa Union(this Fsa fsa, params Fsa[] automata) => automata.Aggregate(fsa, Union);
public static Fsa Concat(this Fsa fsa, params Fsa[] automata) => automata.Aggregate(fsa, Concat);
public static Fst Product(this Fsa first, Fsa second) { var firstTransWithEpsilon = first.Transitions.Union( first.States.Select(s => (From: s, Label: string.Empty, To: s))); var secondTransWithEpsilon = second.Transitions.Union( second.States.Select(s => (From: s, Label: string.Empty, To: s))); var firstTransitionsPerState = firstTransWithEpsilon .GroupBy(t => t.From) .ToDictionary(g => g.Key, g => g); var secondTransitionsPerState = secondTransWithEpsilon .GroupBy(t => t.From) .ToDictionary(g => g.Key, g => g); var productStates = new List <(int, int)>(); foreach (var i1 in first.Initial) { foreach (var i2 in second.Initial) { productStates.Add((i1, i2)); } } var transitions = new HashSet <(int, string, string, int)>(); for (int n = 0; n < productStates.Count; n++) { var(p1, p2) = productStates[n]; var p1Trans = firstTransitionsPerState[p1]; var p2Trans = secondTransitionsPerState[p2]; var productTrans = new List <(string, string, int, int)>(); foreach (var tr1 in p1Trans) { foreach (var tr2 in p2Trans) { productTrans.Add((tr1.Label, tr2.Label, tr1.To, tr2.To)); } } foreach (var(_, _, s1, s2) in productTrans) { if (!productStates.Contains((s1, s2))) { productStates.Add((s1, s2)); } } foreach (var tr in productTrans) { transitions.Add((n, tr.Item1, tr.Item2, productStates.IndexOf((tr.Item3, tr.Item4)))); } } var states = Enumerable.Range(0, productStates.Count); var initial = states.Where(s => first.Initial.Contains(productStates[s].Item1) && second.Initial.Contains(productStates[s].Item2)); var final = states.Where(s => first.Final.Contains(productStates[s].Item1) && second.Final.Contains(productStates[s].Item2)); return(new Fst(states, initial, final, transitions).EpsilonFree().Trim()); }
static Fsa XIgnoreX(Fsa fsa, ISet <char> fsaAlphabet, ISet <char> symbols) => fsa.Identity() .Compose(XintroX(fsaAlphabet, symbols)) .Range();
/* For a given automaton L and a set of symbols S, construct the automaton * which recognizes all words from L with freely introduced symbols from S */ static Fsa Ignore(Fsa fsa, ISet <char> fsaAlphabet, ISet <char> symbols) => fsa.Identity() .Compose(Intro(fsaAlphabet, symbols)) .Range();