public bool IsConsistent() { /* * The following conditions are checked: * - the automaton has at least one state * - all transition target states are "contained" in the automaton * returns Whether the automaton is consistent */ int errors = 0; if (_States.Count == 0) { ++errors; } int startStates = 0; int finalStates = 0; foreach (KeyValuePair <int, State> kvp in _States) { State state = kvp.Value; if (state.IsInitial) { ++startStates; } if (state.IsFinal) { ++finalStates; } for (int t = 0; t < state.Transitions.Count; ++t) { FSTTransition trans = state.Transitions[t]; if (!StateExists(trans.Target)) { ++errors; } } } if (startStates != 1) { ++errors; } // check whether we have at least one final state if (finalStates == 0) { ++errors; } return(errors == 0); }
/// <summary> /// Detects whether the two FSTs are identical. Identity is stronger than equality in that /// the state numbering and all other information must be the same. /// </summary> /// <param name="other">The FST to compare to.</param> /// <returns>true if both FSTs are identical, false otherwise</returns> public bool IsIdentical(FST other) { if (other == null) { throw new ArgumentNullException(); } if (_MaxState != other._MaxState || _StartState != other._StartState || _States.Count != other._States.Count) { return(false); } SortTransitions(); other.SortTransitions(); foreach (KeyValuePair <int, State> kvp in _States) { State otherState; if (!other._States.TryGetValue(kvp.Key, out otherState)) { return(false); } if (kvp.Value.IsFinal != otherState.IsFinal || kvp.Value.IsInitial != otherState.IsInitial || kvp.Value.TransitionCount != otherState.TransitionCount) { return(false); } for (int t = 0; t < kvp.Value.TransitionCount; ++t) { FSTTransition tt = kvp.Value.Transitions[t]; FSTTransition ot = otherState.Transitions[t]; if (tt.Source != ot.Source || tt.Target != ot.Target || tt.Input.Symbol != ot.Input.Symbol || tt.Output.Symbol != ot.Output.Symbol) { return(false); } } } return(true); }
public override FST GetFST() { FST sub = _Content.GetFST(); // catch a couple of special cases if (_Lower == 0 && _Upper == 1 || // optional (?) _Lower == 1 && _Upper == INFINITY || // plus-closure (+) _Lower == 0 && _Upper == INFINITY) // kleene-closure (*) { int subStart = sub.GetStartState(); // the order of the next two tests matters if (_Upper == INFINITY) { List <int> finalStates = sub.GetFinalStates(); /* for each transition ending in a final state, copy that transition to * point to the single start state */ foreach (int source in sub.GetStates()) { IList <FSTTransition> transitions = sub.GetTransitions(source); for (int t = transitions.Count - 1; t >= 0; --t) { FSTTransition trans = transitions[t]; if (finalStates.Contains(trans.Target)) { sub.AddTransition(source, subStart, new Label(trans.Input), new Label(trans.Output)); } } } } if (_Lower == 0) { // optionality or kleene star - simply make start state final sub.SetFinal(subStart, true); } } else { throw new NotImplementedException(); } return(sub); }
public List <FSTTransition> GetIncomingTransitions(int targetState) { List <FSTTransition> result = new List <FSTTransition>(); foreach (KeyValuePair <int, State> kvp in _States) { State state = kvp.Value; for (int t = 0; t < state.Transitions.Count; ++t) { FSTTransition trans = state.Transitions[t]; if (trans.Target == targetState) { result.Add(trans); } } } return(result); }
public void AddTransition(int target, Label input, Label output) { if (!HasTransition(target, input, output)) { FSTTransition t = new FSTTransition(_Id, target, input, output); _Transitions.Add(t); if (_TransitionsSorted && _Transitions.Count > 1) { // compare the transition we just added to the last one in the previous list int tc = _Transitions.Count; if (_Transitions[tc - 1].CompareTo(_Transitions[tc - 2]) <= 0) { _TransitionsSorted = false; } } } }
/// <summary> /// Attempts to traverse the specified transition, given the current match state. /// </summary> /// <param name="input">The string input</param> /// <param name="t">The transition to probe</param> /// <param name="mode">The match mode</param> /// <returns>The new match state or null if the transition cannot be traversed</returns> public MatchState Traverse(string input, FSTTransition t, Matcher.MatchMode mode, bool ignoreCase) { #if false bool consumed; Label output; if (t.CanTraverse(mode, input, _InputPosition, ignoreCase, out output, out consumed)) { MatchState result = new MatchState(this); result._State = t.Target; result.AppendOutput(output); if (consumed) { ++result._ConsumedSymbols; ++result._InputPosition; } return(result); } else { return(null); } #else Label matchLabel; Label outputLabel; switch (mode) { case Matcher.MatchMode.Analyse: matchLabel = t.Input; outputLabel = t.Output; break; case Matcher.MatchMode.Generate: matchLabel = t.Output; outputLabel = t.Input; break; default: throw new Exception("Illegal case constant"); } if (matchLabel.Matches(input, _InputPosition, ignoreCase)) { MatchState result = new MatchState(this); result._State = t.Target; if (outputLabel.IsConsuming) { result._Output.Add(outputLabel); } if (matchLabel.IsConsuming) { ++result._ConsumedSymbols; ++result._InputPosition; } return(result); } return(null); #endif }
/// <summary> /// Eliminate "true" epsilon transitions (where both input and output are eps). Note that /// partial eps transitions (either input or output is eps) will remain. /// </summary> public int EliminateEpsilonTransitions() { // TODO this is a very naive implementation which is slow int result = 0; Dictionary <int, List <int> > epsClosure = new Dictionary <int, List <int> >(); foreach (KeyValuePair <int, State> kvp in _States) { if (HasEpsilonTransitions(kvp.Key)) { List <int> closure = ComputeStateClosure(kvp.Key, false, delegate(FSTTransition t) { return(t.IsEpsilon); }); epsClosure.Add(kvp.Key, closure); if (!kvp.Value.IsFinal) { // if a final state is in the eps closure, then the current state is final kvp.Value.IsFinal = closure.Any(c => IsFinal(c)); } } } if (epsClosure.Count > 0) { // if the start state has an eps closure, it requries special attention if (epsClosure.ContainsKey(_StartState)) { List <int> closure = epsClosure[_StartState]; State startState = _States[_StartState]; // we need to "jump" all eps transitions which means that we need to duplicate // all non-eps transitions starting from any state in the start state's eps closure // to start at the start state as well. foreach (int c in epsClosure[_StartState]) { foreach (FSTTransition t in _States[c].Transitions) { if (!t.IsEpsilon) { startState.AddTransition(t.Target, new Label(t.Input), new Label(t.Output)); } } } } // for each non-eps transition which ends in a state which has an eps closure, // copy that transition to point to each state in the closure foreach (KeyValuePair <int, State> kvp in _States) { List <FSTTransition> transitions = kvp.Value.Transitions; int currentTransitionCount = transitions.Count; for (int p = currentTransitionCount - 1; p >= 0; --p) { FSTTransition t = transitions[p]; if (t.IsEpsilon) { continue; } List <int> closure; if (epsClosure.TryGetValue(t.Target, out closure)) { System.Diagnostics.Debug.Assert(kvp.Key == t.Source && kvp.Value.Id == kvp.Key); foreach (int trg in closure) { kvp.Value.AddTransition(trg, new Label(t.Input), new Label(t.Output)); } } } // delete pure eps transitions for (int p = currentTransitionCount - 1; p >= 0; --p) { if (transitions[p].IsEpsilon) { transitions.RemoveAt(p); ++result; } } } // above elimination may leave non-reachable states DeleteNonreachableStates(); } System.Diagnostics.Debug.Assert(!HasEpsilonTransitions()); return(result); }
public void Concatenate(FST rhs) { List <int> previouslyFinalStates = GetFinalStates(); if (previouslyFinalStates.Count == 0) { throw new Exception("Automaton does not have any final states"); } if (!StateExists(_StartState)) { throw new Exception("Automaton does not have a start state"); } if (!rhs.StateExists(rhs._StartState)) { throw new Exception("RHS Automaton does not have a start state"); } bool lhsStartWasFinal = IsFinal(_StartState); bool rhsStartWasFinal = rhs.IsFinal(rhs._StartState); // the mapping from the state IDs of the RHS automaton. Key is the // original RHS state ID, Value is the new state ID in the source automaton Dictionary <int, int> stateMapping = new Dictionary <int, int>(); // all previously final states become non-final unless the RHS start state is final if (!rhsStartWasFinal) { foreach (int pf in previouslyFinalStates) { SetFinal(pf, false); } } // copy over the states foreach (KeyValuePair <int, State> rhsState in rhs._States) { int newState = AddState(); stateMapping.Add(rhsState.Value.Id, newState); // final states in the RHS automaton remain final if (rhsState.Value.IsFinal) { SetFinal(newState, true); } } // now that all states exist, copy over the RHS transitions foreach (KeyValuePair <int, State> rhsState in rhs._States) { foreach (FSTTransition t in rhsState.Value.Transitions) { AddTransition(stateMapping[t.Source], stateMapping[t.Target], new Label(t.Input), new Label(t.Output)); } } // next, link the two automatons. // first, each transition which ends in a previously final state is // copied into a transition to the previous start state of RHS int newRhsStart = stateMapping[rhs._StartState]; foreach (KeyValuePair <int, State> lhsState in _States) { State testState = lhsState.Value; List <FSTTransition> transitions = testState.Transitions; // Take care with this iteration as the loop adds to the state's transitions for (int transition = transitions.Count - 1; transition >= 0; --transition) { FSTTransition link = transitions[transition]; if (previouslyFinalStates.Contains(link.Target)) { testState.AddTransition(newRhsStart, new Label(link.Input), new Label(link.Output)); } } } if (lhsStartWasFinal) { // need to introduce an eps transition to the rhs start state AddTransition(_StartState, newRhsStart, new Label(Label.SpecialSymbolEpsilon), new Label(Label.SpecialSymbolEpsilon)); } Clean(); }