1 // See www.openfst.org for extensive documentation on this weighted
2 // finite-state transducer library.
4 // Class to draw a binary FST by producing a text file in dot format, a helper
5 // class to fstdraw.cc.
7 #ifndef FST_SCRIPT_DRAW_IMPL_H_
8 #define FST_SCRIPT_DRAW_IMPL_H_
16 #include <fst/script/fst-class.h>
20 // Print a binary FST in GraphViz textual format (helper class for fstdraw.cc).
21 // WARNING: Stand-alone use not recommend.
25 using Label = typename Arc::Label;
26 using StateId = typename Arc::StateId;
27 using Weight = typename Arc::Weight;
29 FstDrawer(const Fst<Arc> &fst, const SymbolTable *isyms,
30 const SymbolTable *osyms, const SymbolTable *ssyms, bool accep,
31 const string &title, float width, float height, bool portrait,
32 bool vertical, float ranksep, float nodesep, int fontsize,
33 int precision, const string &float_format, bool show_weight_one)
38 accep_(accep && fst.Properties(kAcceptor, true)),
48 precision_(precision),
49 float_format_(float_format),
50 show_weight_one_(show_weight_one) {}
52 // Draw Fst to an output buffer (or stdout if buf = 0)
53 void Draw(std::ostream *strm, const string &dest) {
55 SetStreamState(ostrm_);
57 StateId start = fst_.Start();
58 if (start == kNoStateId) return;
59 PrintString("digraph FST {\n");
61 PrintString("rankdir = BT;\n");
63 PrintString("rankdir = LR;\n");
65 PrintString("size = \"");
70 if (!dest_.empty()) PrintString("label = \"" + title_ + "\";\n");
71 PrintString("center = 1;\n");
73 PrintString("orientation = Portrait;\n");
75 PrintString("orientation = Landscape;\n");
77 PrintString("ranksep = \"");
80 PrintString("nodesep = \"");
83 // Initial state first.
85 for (StateIterator<Fst<Arc>> siter(fst_); !siter.Done(); siter.Next()) {
86 const auto s = siter.Value();
87 if (s != start) DrawState(s);
93 void SetStreamState(std::ostream* strm) const {
94 strm->precision(precision_);
95 if (float_format_ == "e")
96 strm->setf(std::ios_base::scientific, std::ios_base::floatfield);
97 if (float_format_ == "f")
98 strm->setf(std::ios_base::fixed, std::ios_base::floatfield);
99 // O.w. defaults to "g" per standard lib.
102 void PrintString(const string &str) const { *ostrm_ << str; }
104 // Escapes backslash and double quote if these occur in the string. Dot will
105 // not deal gracefully with these if they are not escaped.
106 static string Escape(const string &str) {
109 if (c == '\\' || c == '"') ns.push_back('\\');
115 void PrintId(StateId id, const SymbolTable *syms, const char *name) const {
117 auto symbol = syms->Find(id);
118 if (symbol.empty()) {
119 FSTERROR() << "FstDrawer: Integer " << id
120 << " is not mapped to any textual symbol"
121 << ", symbol table = " << syms->Name()
122 << ", destination = " << dest_;
125 PrintString(Escape(symbol));
127 PrintString(std::to_string(id));
131 void PrintStateId(StateId s) const { PrintId(s, ssyms_, "state ID"); }
133 void PrintILabel(Label label) const {
134 PrintId(label, isyms_, "arc input label");
137 void PrintOLabel(Label label) const {
138 PrintId(label, osyms_, "arc output label");
141 void PrintWeight(Weight w) const {
142 // Weight may have double quote characters in it, so escape it.
143 PrintString(Escape(ToString(w)));
147 void Print(T t) const { *ostrm_ << t; }
150 string ToString(T t) const {
151 std::stringstream ss;
157 void DrawState(StateId s) const {
159 PrintString(" [label = \"");
161 const auto weight = fst_.Final(s);
162 if (weight != Weight::Zero()) {
163 if (show_weight_one_ || (weight != Weight::One())) {
167 PrintString("\", shape = doublecircle,");
169 PrintString("\", shape = circle,");
171 if (s == fst_.Start()) {
172 PrintString(" style = bold,");
174 PrintString(" style = solid,");
176 PrintString(" fontsize = ");
179 for (ArcIterator<Fst<Arc>> aiter(fst_, s); !aiter.Done(); aiter.Next()) {
180 const auto &arc = aiter.Value();
184 Print(arc.nextstate);
185 PrintString(" [label = \"");
186 PrintILabel(arc.ilabel);
189 PrintOLabel(arc.olabel);
191 if (show_weight_one_ || (arc.weight != Weight::One())) {
193 PrintWeight(arc.weight);
195 PrintString("\", fontsize = ");
201 const Fst<Arc> &fst_;
202 const SymbolTable *isyms_; // ilabel symbol table.
203 const SymbolTable *osyms_; // olabel symbol table.
204 const SymbolTable *ssyms_; // slabel symbol table.
205 bool accep_; // Print as acceptor when possible.
206 std::ostream *ostrm_; // Drawn FST destination.
207 string dest_; // Drawn FST destination name.
218 string float_format_;
219 bool show_weight_one_;
221 FstDrawer(const FstDrawer &) = delete;
222 FstDrawer &operator=(const FstDrawer &) = delete;
227 #endif // FST_SCRIPT_DRAW_IMPL_H_