public static SST <SYMBOL> Union(params SST <SYMBOL>[] taus) { if (taus.Length == 0) { throw SSTException.NoSSTsInUnion(); } if (taus.Length == 1) { return(taus[0]); } var finalStates = new List <int>(taus.Sum(tau => tau.FinalStates.Count())); var moves = new List <Move <Label <SYMBOL> > >(taus.Length + taus.Sum(tau => tau.Moves.Count())); var alphabet = taus.Select(tau => tau.Alphabet).Aggregate(Set <SYMBOL> .Union); int offset = 0; Func <int, int> translate = state => offset + 1 + state; foreach (SST <SYMBOL> tau in taus.Select(tau => tau.Normalize())) { finalStates.AddRange(tau.FinalStates.Select(translate)); moves.Add(new Move <Label <SYMBOL> >(0, translate(tau.InitialState), new Label <SYMBOL>(null, null))); moves.AddRange(tau.Moves.Select(move => new Move <Label <SYMBOL> >( translate(move.SourceState), translate(move.TargetState), move.Label ))); offset += tau.States.Count(); } return(new SST <SYMBOL>(0, finalStates, moves, alphabet)); }
/// <summary> /// Compose transducers T1 and T2, resulting in transducer equivalent to applying T2 after T1. /// </summary> public static SST <SYMBOL> Compose(SST <SYMBOL> tau1, SST <SYMBOL> tau2) { if (tau1.Algebra != tau2.Algebra) { throw SSTException.IncompatibleAlphabets(); } LabelAlgebra <SYMBOL> algebra = tau1.Algebra; var stack = new Stack <Tuple <int, int> >(); var finalStates = new List <int>(); var moves = new List <Move <Label <SYMBOL> > >(); var stateDict = new Dictionary <Tuple <int, int>, int>(); int id = 0; var init = new Tuple <int, int>(tau1.InitialState, tau2.InitialState); stateDict[init] = id++; stack.Push(init); while (stack.Count > 0) { Tuple <int, int> sourcePair = stack.Pop(); int state1 = sourcePair.Item1; int state2 = sourcePair.Item2; foreach (Move <Label <SYMBOL> > move1 in tau1.GetMovesFrom(state1)) { foreach (Move <Label <SYMBOL> > move2 in tau2.GetMovesFrom(state2)) { Label <SYMBOL> newLabel = algebra.Combine(move1.Label, move2.Label); if (!algebra.IsSatisfiable(newLabel)) { continue; } var targetPair = new Tuple <int, int>(move1.TargetState, move2.TargetState); int targetState; if (!stateDict.TryGetValue(targetPair, out targetState)) { stateDict[targetPair] = targetState = id++; stack.Push(targetPair); if (tau1.IsFinalState(move1.TargetState) && tau2.IsFinalState(move2.TargetState)) { finalStates.Add(targetState); } } moves.Add(new Move <Label <SYMBOL> >(stateDict[sourcePair], targetState, newLabel)); } } } return(new SST <SYMBOL>(0, finalStates, moves)); }
/// <summary> /// Applies this transducer to automaton M in order to create a new automaton /// that accepts the translations of all words in L(M). /// </summary> public SSA <SYMBOL> Apply(SSA <SYMBOL> m) { if (this.Algebra.Alphabet != m.Algebra.Alphabet) { throw SSTException.IncompatibleAlphabets(); } m = m.RemoveEpsilons(); Automaton <Label <SYMBOL> > tau = this.automaton; var stack = new Stack <Tuple <int, int> >(); var finalStates = new List <int>(); var moves = new List <Move <Predicate <SYMBOL> > >(); var stateDict = new Dictionary <Tuple <int, int>, int>(); int id = 0; var init = new Tuple <int, int>(tau.InitialState, m.InitialState); stateDict[init] = id++; // initial state will be 0 stack.Push(init); Action <Tuple <int, int>, Tuple <int, int>, Predicate <SYMBOL> > addMove = (sourcePair, targetPair, label) => { int targetState; if (!stateDict.TryGetValue(targetPair, out targetState)) { stateDict[targetPair] = targetState = id++; stack.Push(targetPair); } moves.Add(new Move <Predicate <SYMBOL> >(stateDict[sourcePair], targetState, label)); }; while (stack.Count > 0) { Tuple <int, int> sourcePair = stack.Pop(); int tauState = sourcePair.Item1; int mState = sourcePair.Item2; foreach (Move <Label <SYMBOL> > tauMove in tau.GetMovesFrom(tauState)) { if (tauMove.Label.Input == null) { addMove( sourcePair, new Tuple <int, int>(tauMove.TargetState, mState), tauMove.Label.IsIdentity ? null : tauMove.Label.Output ); continue; } foreach (Move <Predicate <SYMBOL> > mMove in m.GetMovesFrom(mState)) { if (!m.Algebra.IsSatisfiable(tauMove.Label.Input & mMove.Label)) { continue; } Predicate <SYMBOL> newLabel; if (tauMove.Label.IsIdentity) { newLabel = tauMove.Label.Input & mMove.Label; } else { newLabel = tauMove.Label.Output; if (newLabel != null && !m.Algebra.IsSatisfiable(newLabel)) { continue; } } addMove( sourcePair, new Tuple <int, int>(tauMove.TargetState, mMove.TargetState), newLabel ); } } } foreach (var pair in stateDict) { if (tau.IsFinalState(pair.Key.Item1) && m.IsFinalState(pair.Key.Item2)) { finalStates.Add(pair.Value); } } return(new SSA <SYMBOL>(0, finalStates, moves, m.Algebra.Alphabet)); }