Ejemplo n.º 1
0
 public bool AreEquivalent(Label <SYMBOL> l1, Label <SYMBOL> l2)
 {
     if (l1.IsIdentity != l2.IsIdentity)
     {
         Set <SYMBOL> i1 = pa.InclusiveSet(l1.Input);
         Set <SYMBOL> i2 = pa.InclusiveSet(l2.Input);
         Set <SYMBOL> o  = pa.InclusiveSet(l1.IsIdentity ? l2.Output : l1.Output);
         return(i1.Count == 1 && i2.Count == 1 && o.Count == 1 && i1 == i2 && i2 == o);
     }
     if (l1.IsIdentity)              // l2.IsIdentity implicit
     {
         return(pa.AreEquivalent(l1.Input, l2.Input));
     }
     return(pa.AreEquivalent(l1.Input, l2.Input) && pa.AreEquivalent(l1.Output, l2.Output));
 }
Ejemplo n.º 2
0
        /* format spec at http://web.eecs.umich.edu/~radev/NLP-fall2015/resources/fsm_archive/fsm.5.html */
        private static void PrintAutomatonFSM(
            StreamWriter file, AutomatonType type, string name, Dictionary <int, string> stateNames,
            PredicateAlgebra <SYMBOL> algebra, List <int> states, List <SYMBOL> alphabet,
            List <Move <ILabel <SYMBOL> > > moves, int initialState, List <int> finalStates,
            string stateSymbolsFileName = null, string inputSymbolsFileName = null, string outputSymbolsFileName = null)
        {
            // map symbols to numeric IDs
            var symbolDict = new Dictionary <SYMBOL, int>(alphabet.Count);
            int id         = 1; // 0 reserved for epsilon

            foreach (SYMBOL symbol in alphabet)
            {
                symbolDict[symbol] = id++;
            }

            // print state/symbol as number if corresponding symbols file unspecified,
            // otherwise print as string and map it to number in symbols file

            Func <int, string>                state2str          = state => (stateSymbolsFileName == null) ? state.ToString() : stateNames[state];
            Func <SYMBOL, string>             input2str          = symbol => (inputSymbolsFileName == null) ? symbolDict[symbol].ToString() : symbol.ToString();
            Func <SYMBOL, string>             output2str         = symbol => (outputSymbolsFileName == null) ? symbolDict[symbol].ToString() : symbol.ToString();
            Action <Move <ILabel <SYMBOL> > > printPredicateMove = move => {
                int sourceState = move.SourceState;
                var predicate   = (Predicate <SYMBOL>)move.Label;
                int targetState = move.TargetState;
                if (predicate == null)
                {
                    file.WriteLine("{0} {1} 0", state2str(sourceState), state2str(targetState));
                }
                else
                {
                    foreach (SYMBOL symbol in algebra.InclusiveSet(predicate))
                    {
                        file.WriteLine("{0} {1} {2}", state2str(sourceState), state2str(targetState), input2str(symbol));
                    }
                }
            };
            Action <Move <ILabel <SYMBOL> > > printLabelMove = move => {
                int sourceState = move.SourceState;
                var label       = (Label <SYMBOL>)move.Label;
                int targetState = move.TargetState;
                if (label.IsIdentity)
                {
                    if (label.Input == null)
                    {
                        file.WriteLine("{0} {1} 0 0", state2str(sourceState), state2str(targetState));
                    }
                    else
                    {
                        foreach (SYMBOL symbol in algebra.InclusiveSet(label.Input))
                        {
                            file.WriteLine("{0} {1} {2} {3}",
                                           state2str(sourceState), state2str(targetState), input2str(symbol), output2str(symbol));
                        }
                    }
                }
                else
                {
                    if (label.Input == null)
                    {
                        if (label.Output == null)
                        {
                            file.WriteLine("{0} {1} 0 0", state2str(sourceState), state2str(targetState));
                        }
                        else
                        {
                            foreach (SYMBOL output in algebra.InclusiveSet(label.Output))
                            {
                                file.WriteLine("{0} {1} 0 {2}", state2str(sourceState), state2str(targetState), output2str(output));
                            }
                        }
                    }
                    else
                    {
                        foreach (SYMBOL input in algebra.InclusiveSet(label.Input))
                        {
                            if (label.Output == null)
                            {
                                file.WriteLine("{0} {1} {2} 0", state2str(sourceState), state2str(targetState), input2str(input));
                            }
                            else
                            {
                                foreach (SYMBOL output in algebra.InclusiveSet(label.Output))
                                {
                                    file.WriteLine("{0} {1} {2} {3}",
                                                   state2str(sourceState), state2str(targetState), input2str(input), output2str(output));
                                }
                            }
                        }
                    }
                }
            };
            Action <Move <ILabel <SYMBOL> > > printMove = (type == AutomatonType.SSA) ?
                                                          printPredicateMove : printLabelMove;

            // print moves
            foreach (Move <ILabel <SYMBOL> > move in moves)
            {
                printMove(move);
            }
            // print final states
            foreach (int finalState in states)
            {
                file.WriteLine((stateSymbolsFileName == null) ? finalState.ToString() : stateNames[finalState]);
            }

            if (stateSymbolsFileName != null)
            {
                var stateFile = new StreamWriter(stateSymbolsFileName);
                try {
                    foreach (KeyValuePair <int, string> item in stateNames)
                    {
                        stateFile.WriteLine("{0} {1}", item.Value, item.Key);
                    }
                } finally {
                    stateFile.Close();
                }
            }

            string[] symbolsFileNames = (type == AutomatonType.SSA) ?
                                        new string[] { inputSymbolsFileName } :
            new string[] { inputSymbolsFileName, outputSymbolsFileName };
            foreach (string symbolsFileName in symbolsFileNames)
            {
                if (symbolsFileName != null)
                {
                    var symbolsFile = new StreamWriter(symbolsFileName);
                    try {
                        foreach (KeyValuePair <SYMBOL, int> item in symbolDict)
                        {
                            symbolsFile.WriteLine("{0} {1}", item.Key, item.Value);
                        }
                    } finally {
                        symbolsFile.Close();
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /* FSA format spec at http://www.let.rug.nl/~vannoord/Fsa/Manual/node5.html#anc1 */
        private static void PrintAutomatonFSA(
            StreamWriter file, AutomatonType type, string name, Dictionary <int, string> stateNames,
            PredicateAlgebra <SYMBOL> algebra, List <int> states, List <SYMBOL> alphabet,
            List <Move <ILabel <SYMBOL> > > moves, int initialState, List <int> finalStates,
            string stateSymbolsFileName = null, string inputSymbolsFileName = null, string outputSymbolsFileName = null)
        {
            var transitions = new List <Move <ILabel <SYMBOL> > >(); // non-epsilon moves
            var jumps       = new List <Tuple <int, int> >();        // epsilon moves

            foreach (Move <ILabel <SYMBOL> > move in moves)
            {
                if (move.IsEpsilon)
                {
                    jumps.Add(new Tuple <int, int>(move.SourceState, move.TargetState));
                }
                else
                {
                    transitions.Add(move);
                }
            }

            Func <ILabel <SYMBOL>, string> printPredicate = ilabel => {
                var predicate = (Predicate <SYMBOL>)ilabel;
                if (predicate == null)  // epsilon (only for transducers)
                {
                    return("[]");
                }
                // add quotes if necessary
                Func <SYMBOL, string> sanitizeSymbol = symbol => {
                    string s = symbol.ToString();
                    if (char.IsUpper(s[0]) || s.Any(ch => char.IsWhiteSpace(ch)) || (s[0] == '0' && s.Length > 1))
                    {
                        return("'" + s + "'");
                    }
                    return(s);
                };
                // `in([a])` may just be written as `a`
                if (algebra.InclusiveSet(predicate).Count == 1)
                {
                    return(sanitizeSymbol(algebra.InclusiveSet(predicate).First()));
                }
                string        typeName = (predicate.Type == PredicateType.In) ? "in" : "not_in";
                List <string> symbols  = predicate.Set.Select(sanitizeSymbol).ToList();
                symbols.Sort();
                return(string.Format("{0}([{1}])", typeName, string.Join(",", symbols)));
            };
            Func <ILabel <SYMBOL>, string> printLabel = ilabel => {
                var label = (Label <SYMBOL>)ilabel;
                return(label.IsIdentity ?
                       string.Format("$@({0})/$@({0})", printPredicate(label.Input)) :
                       string.Format("{0}/{1}", printPredicate(label.Input), printPredicate(label.Output)));
            };
            Func <ILabel <SYMBOL>, string> printILabel = (type == AutomatonType.SSA) ?
                                                         printPredicate : printLabel;

            file.WriteLine("%% {0} {1}", (type == AutomatonType.SSA) ? "Recognizer" : "Transducer", name ?? "");
            file.WriteLine("%% Automatically generated by ARMC.");
            file.WriteLine("%% For more info, cf. http://www.let.rug.nl/~vannoord/Fsa/");
            file.WriteLine();
            file.WriteLine("fa(");
            if (type == AutomatonType.SSA)
            {
                file.WriteLine("    r(fsa_preds),");
            }
            else
            {
                file.WriteLine("    t(fsa_preds,fsa_preds),");
            }
            file.WriteLine("    % number of states");
            file.WriteLine("    {0},", states.Count);
            file.WriteLine("    % start states");
            file.WriteLine("    [ {0} ],", initialState);
            file.WriteLine("    % final states");
            // put up to 10 final states on one line
            int i = 0;

            FSAWriteList(
                file,
                finalStates.GroupBy(state => i++ / 10).Select(group => group.ToList()),
                stateList => string.Join(",", stateList)
                );
            file.WriteLine("    ],");
            file.WriteLine("    % moves");
            FSAWriteList(file, transitions, (move => string.Format("trans({0},{1},{2})", move.SourceState, printILabel(move.Label), move.TargetState)));
            file.WriteLine("    % jumps");
            FSAWriteList(file, jumps, (jump => string.Format("jump({0},{1})", jump.Item1, jump.Item2)), false);
            file.WriteLine(").");
            file.WriteLine();
        }
Ejemplo n.º 4
0
        /* format spec at http://www.graphviz.org/doc/info/lang.html */
        private static void PrintAutomatonDot(
            StreamWriter file, AutomatonType type, string name, Dictionary <int, string> stateNames,
            PredicateAlgebra <SYMBOL> algebra, List <int> states, List <SYMBOL> alphabet,
            List <Move <ILabel <SYMBOL> > > moves, int initialState, List <int> finalStates,
            string stateSymbolsFileName = null, string inputSymbolsFileName = null, string outputSymbolsFileName = null)
        {
            // group labels for moves with same source and target state (reduce edges in graph)
            var transGroups = moves.GroupBy(
                move => new Tuple <int, int>(move.SourceState, move.TargetState),
                move => move.Label,
                (key, labels) => new Tuple <int, List <ILabel <SYMBOL> >, int>(key.Item1, labels.ToList(), key.Item2)
                );

            // create subscripts and superscripts based on LaTeX-like markup in state names
            // e.g. q_0 becomes <q<sub>0</sub>>, q_{42} becomes <q<sub>42</sub>>, q_M^2 becomes <q<sub>M</sub><sup>2</sup>>
            var regexSubSingle             = new Regex(@"_([^{])");
            var regexSubGroup              = new Regex(@"_{([^}]*)}");
            var regexSuperSingle           = new Regex(@"\^([^{])");
            var regexSuperGroup            = new Regex(@"\^{([^}]*)}");
            Func <int, string> stateToHTML = delegate(int state) {
                string stateName = stateNames[state];
                stateName = regexSubSingle.Replace(stateName, "<sub>$1</sub>");
                stateName = regexSubGroup.Replace(stateName, "<sub>$1</sub>");
                stateName = regexSuperSingle.Replace(stateName, "<sup>$1</sup>");
                stateName = regexSuperGroup.Replace(stateName, "<sup>$1</sup>");
                return(stateName);
            };

            Func <SYMBOL, string> printSymbol = symbol => symbol.ToString()
                                                .Replace("<", "&lt;").Replace(">", "&gt;")
                                                .Replace("[", "&#91;").Replace("]", "&#93;");

            Func <ILabel <SYMBOL>, string> printPredicate = ilabel => {
                var predicate = (Predicate <SYMBOL>)ilabel;
                if (predicate == null)
                {
                    return("&epsilon;");
                }
                if (algebra.InclusiveSet(predicate).Count == 1)
                {
                    return(string.Format("<i>{0}</i>", printSymbol(algebra.InclusiveSet(predicate).First())));
                }
                string typeSymbol = (predicate.Type == PredicateType.In) ? "&isin;" : "&notin;";  // unicode math set symbols
                // sort symbols and put in italics
                var symbols = new List <SYMBOL>(predicate.Set);
                symbols.Sort();
                var symbolsFormatted         = new List <string>(symbols.Select(symbol => string.Format("<i>{0}</i>", symbol)));
                Func <int, int, int> ceilDiv = (x, y) => (x - 1) / y + 1;
                int groupSize = 5;
                if (symbols.Count > 1)
                {
                    while (ceilDiv(symbols.Count, groupSize - 1) == ceilDiv(symbols.Count, groupSize))
                    {
                        groupSize--;
                    }
                }
                int    i      = 0;
                string joined = string.Join(",<br/>", symbols
                                            .Select(printSymbol)
                                            .Select(symbol => string.Format("<i>{0}</i>", symbol))
                                            .GroupBy(symbol => i++ / groupSize)
                                            .Select(group => string.Join(", ", group.ToList()))
                                            );
                return(typeSymbol + "{" + joined + "}");
            };
            Func <ILabel <SYMBOL>, string> printLabel = ilabel => {
                var label = (Label <SYMBOL>)ilabel;
                return(label.IsIdentity ?
                       string.Format("{0}<b>/</b>&#x1d704;", printPredicate(label.Input)) :
                       string.Format("{0}<b>/</b>{1}", printPredicate(label.Input), printPredicate(label.Output)));
            };
            Func <ILabel <SYMBOL>, string> printILabel = (type == AutomatonType.SSA) ?
                                                         printPredicate : printLabel;

            file.WriteLine("digraph {");
            file.WriteLine("    rankdir=LR;"); // left-to-right direction more readable for automata
            if (name != null)                  // print automaton name
            {
                file.WriteLine("    label=<{0}:>;", name);
                file.WriteLine("    labelloc=top;");
                file.WriteLine("    labeljust=left;");
            }
            // final states have double circle
            file.Write("    node [shape=doublecircle];");
            foreach (int finalState in finalStates)
            {
                file.Write(" {0};", finalState);
            }
            file.WriteLine();
            file.WriteLine("    node [shape=circle];");
            // invisible zero-width dummy node as source of arrow to initial state
            file.WriteLine("    dummy_node [style=invis,width=0,fixedsize=true,label=\"\"];");
            file.WriteLine("    dummy_node -> {0} [len=0.2,penwidth=2.0];", initialState);
            foreach (Tuple <int, List <ILabel <SYMBOL> >, int> trans in transGroups)
            {
                int sourceState = trans.Item1;
                List <ILabel <SYMBOL> > labels = trans.Item2;
                int targetState = trans.Item3;
                file.WriteLine("    {0} -> {1} [label=<{2}>];",
                               sourceState, targetState, string.Join(",<br/>", labels.Select(printILabel))
                               );
            }
            foreach (int state in states)
            {
                file.WriteLine("    {0} [label=<{1}>];", state, stateToHTML(state));
            }
            file.WriteLine("}");
            file.WriteLine();
        }