/// <summary> /// Write the automaton in dgml format into the textwriter. /// </summary> public void Write <S>(IAutomaton <S> fa) { var nonEpsilonMoves = new Dictionary <(int, int), List <S> >(); var epsilonmoves = new List <Move <S> >(); var nonEpsilonStates = new HashSet <int>(); foreach (Move <S> move in fa.GetMoves()) { if (move.IsEpsilon) { epsilonmoves.Add(move); } else { nonEpsilonStates.Add(move.SourceState); var p = (move.SourceState, move.TargetState); if (!nonEpsilonMoves.TryGetValue(p, out List <S>?rules)) { rules = new List <S>(); nonEpsilonMoves[p] = rules; } Debug.Assert(move.Label is not null); rules.Add(move.Label); } } _tw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); _tw.WriteLine("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\" ZoomLevel=\"1.5\" GraphDirection=\"TopToBottom\" >"); _tw.WriteLine("<Nodes>"); _tw.WriteLine("<Node Id=\"dfa\" Label=\" \" Group=\"Collapsed\" Category=\"DFA\" DFAInfo=\"{0}\" />", GetDFAInfo(fa)); _tw.WriteLine("<Node Id=\"dfainfo\" Category=\"DFAInfo\" Label=\"{0}\"/>", GetDFAInfo(fa)); if (_onlyDFAinfo) { _tw.WriteLine("</Nodes>"); } else { foreach (int state in fa.GetStates()) { _tw.WriteLine("<Node Id=\"{0}\" Label=\"{0}\" Category=\"State\" Group=\"{1}\" StateInfo=\"{2}\">", state, _hideStateInfo ? "Collapsed" : "Expanded", GetStateInfo(fa, state)); if (state == fa.InitialState) { _tw.WriteLine("<Category Ref=\"InitialState\" />"); } if (fa.IsFinalState(state)) { _tw.WriteLine("<Category Ref=\"FinalState\" />"); } _tw.WriteLine("</Node>"); _tw.WriteLine("<Node Id=\"{0}info\" Label=\"{1}\" Category=\"StateInfo\"/>", state, GetStateInfo(fa, state)); } _tw.WriteLine("</Nodes>"); _tw.WriteLine("<Links>"); _tw.WriteLine("<Link Source=\"dfa\" Target=\"{0}\" Label=\"{1}\" Category=\"StartTransition\" />", fa.InitialState, fa.DescribeStartLabel()); _tw.WriteLine("<Link Source=\"dfa\" Target=\"dfainfo\" Label=\"\" Category=\"Contains\" />"); foreach (Move <S> move in epsilonmoves) { _tw.WriteLine("<Link Source=\"{0}\" Target=\"{1}\" Category=\"EpsilonTransition\" />", move.SourceState, move.TargetState); } foreach (KeyValuePair <(int, int), List <S> > move in nonEpsilonMoves) { _tw.WriteLine(GetNonFinalRuleInfo(fa, move.Key.Item1, move.Key.Item2, move.Value)); } foreach (int state in fa.GetStates()) { _tw.WriteLine("<Link Source=\"{0}\" Target=\"{0}info\" Category=\"Contains\" />", state); } _tw.WriteLine("</Links>"); WriteCategoriesAndStyles(); } _tw.WriteLine("</DirectedGraph>"); }
/// <summary> /// Write the automaton in dgml format. /// </summary> /// <param name="fa">the automaton to write</param> /// <param name="tw">text writer for the output</param> public static void AutomatonToDgml <S>(int k, IAutomaton <S> fa, string name, System.IO.TextWriter tw, Func <S, string> describeS = null) { ITransducer <S> faf = fa as ITransducer <S>; bool isTransducer = (faf != null); Func <S, bool> isfinal = lab => { return(isTransducer ? faf.IsFinalRule(lab) : false); }; var finalMoves = new Dictionary <int, List <S> >(); var nonFinalMoves = new Dictionary <Tuple <int, int>, List <S> >(); var epsilonmoves = new List <Move <S> >(); var nonEpsilonStates = new HashSet <int>(); Func <int, bool> IsEpsilonState = (s => !nonEpsilonStates.Contains(s)); foreach (var move in fa.GetMoves()) { if (move.IsEpsilon) { epsilonmoves.Add(move); } else if (isfinal(move.Label) && !(faf.IsGuardTrue(move.Label) && faf.GetYieldsLength(move.Label) == 0)) { List <S> rules; if (!finalMoves.TryGetValue(move.SourceState, out rules)) { rules = new List <S>(); finalMoves[move.SourceState] = rules; } rules.Add(move.Label); } else if (!isfinal(move.Label)) { nonEpsilonStates.Add(move.SourceState); List <S> rules; var p = new Tuple <int, int>(move.SourceState, move.TargetState); if (!nonFinalMoves.TryGetValue(p, out rules)) { rules = new List <S>(); nonFinalMoves[p] = rules; } rules.Add(move.Label); } } tw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); tw.WriteLine("<DirectedGraph xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\" ZoomLevel=\"1.5\" GraphDirection=\"TopToBottom\" >"); tw.WriteLine("<Nodes>"); tw.WriteLine("<Node Id=\"init\" Label=\"{0}\" Stroke=\"white\" Background=\"white\"/>", name); foreach (int state in fa.GetStates()) { if (state == fa.InitialState && fa.IsFinalState(state)) { tw.WriteLine("<Node Id=\"{0}\" Label=\"{1}\" Category=\"State\" >", state, fa.DescribeState(state)); if (!finalMoves.ContainsKey(state)) { //if (IsEpsilonState(state)) // tw.WriteLine("<Category Ref=\"EpsilonState\" />"); //else tw.WriteLine("<Category Ref=\"FinalState\" />"); } //tw.WriteLine("<Category Ref=\"InitialState\" />"); tw.WriteLine("</Node>"); if (finalMoves.ContainsKey(state)) { tw.WriteLine("<Node Id=\"f{0}\" Label=\" \" Category=\"State\" >", state); tw.WriteLine("<Category Ref=\"FinalState\" />"); tw.WriteLine("<Category Ref=\"SinkState\" />"); tw.WriteLine("</Node>"); } } else if (state == fa.InitialState) { tw.WriteLine("<Node Id=\"{0}\" Label=\"{1}\" Category=\"State\" >", state, fa.DescribeState(state)); tw.WriteLine("<Category Ref=\"InitialState\" />"); tw.WriteLine("</Node>"); } else if (fa.IsFinalState(state)) { tw.WriteLine("<Node Id=\"{0}\" Label=\"{1}\" Category=\"State\" >", state, fa.DescribeState(state)); if (!finalMoves.ContainsKey(state)) { //if (IsEpsilonState(state)) // tw.WriteLine("<Category Ref=\"EpsilonState\" />"); //else tw.WriteLine("<Category Ref=\"FinalState\" />"); } tw.WriteLine("</Node>"); if (finalMoves.ContainsKey(state)) { tw.WriteLine("<Node Id=\"f{0}\" Label=\" \" Category=\"State\" >", state); tw.WriteLine("<Category Ref=\"FinalState\" />"); tw.WriteLine("<Category Ref=\"SinkState\" />"); tw.WriteLine("</Node>"); } } else { tw.WriteLine("<Node Id=\"{0}\" Label=\"{1}\" Category=\"State\" />", state, fa.DescribeState(state)); } } tw.WriteLine("</Nodes>"); tw.WriteLine("<Links>"); tw.WriteLine("<Link Source=\"init\" Target=\"{0}\" Label=\"{1}\" Category=\"StartTransition\" />", fa.InitialState, fa.DescribeStartLabel()); foreach (var move in epsilonmoves) { tw.WriteLine("<Link Source=\"{0}\" Target=\"{1}\" Category=\"EpsilonTransition\" />", move.SourceState, move.TargetState); } foreach (var move in nonFinalMoves) { tw.WriteLine(GetNonFinalRuleInfo(k, fa, faf, move.Key.Item1, move.Key.Item2, move.Value, describeS)); } foreach (var move in finalMoves) { tw.WriteLine(GetFinalRuleInfo(k, faf, move.Key, move.Value)); } tw.WriteLine("</Links>"); WriteCategoriesAndStyles(tw); tw.WriteLine("</DirectedGraph>"); }