FST  openfst-1.8.3
OpenFst Library
draw-impl.h
Go to the documentation of this file.
1 // Copyright 2005-2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the 'License');
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an 'AS IS' BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // See www.openfst.org for extensive documentation on this weighted
16 // finite-state transducer library.
17 //
18 // Class to draw a binary FST by producing a text file in dot format, a helper
19 // class to fstdraw.cc.
20 
21 #ifndef FST_SCRIPT_DRAW_IMPL_H_
22 #define FST_SCRIPT_DRAW_IMPL_H_
23 
24 #include <iomanip>
25 #include <ios>
26 #include <ostream>
27 #include <sstream>
28 #include <string>
29 
30 #include <fst/log.h>
31 #include <fst/fst.h>
32 #include <fst/properties.h>
33 #include <fst/symbol-table.h>
34 #include <fst/util.h>
35 #include <fst/script/fst-class.h>
36 #include <string_view>
37 
38 namespace fst {
39 
40 // Print a binary FST in GraphViz textual format (helper class for fstdraw.cc).
41 // WARNING: Stand-alone use not recommend.
42 template <class Arc>
43 class FstDrawer {
44  public:
45  using Label = typename Arc::Label;
46  using StateId = typename Arc::StateId;
47  using Weight = typename Arc::Weight;
48 
49  FstDrawer(const Fst<Arc> &fst, const SymbolTable *isyms,
50  const SymbolTable *osyms, const SymbolTable *ssyms, bool accep,
51  std::string_view title, float width, float height, bool portrait,
52  bool vertical, float ranksep, float nodesep, int fontsize,
53  int precision, std::string_view float_format,
54  bool show_weight_one)
55  : fst_(fst),
56  isyms_(isyms),
57  osyms_(osyms),
58  ssyms_(ssyms),
59  accep_(accep && fst.Properties(kAcceptor, true)),
60  title_(title),
61  width_(width),
62  height_(height),
63  portrait_(portrait),
64  vertical_(vertical),
65  ranksep_(ranksep),
66  nodesep_(nodesep),
67  fontsize_(fontsize),
68  precision_(precision),
69  float_format_(float_format),
70  show_weight_one_(show_weight_one) {}
71 
72  // Draws FST to an output buffer.
73  void Draw(std::ostream &strm, std::string_view dest) {
74  SetStreamState(strm);
75  dest_ = std::string(dest);
76  const auto start = fst_.Start();
77  if (start == kNoStateId) return;
78  strm << "digraph FST {\n";
79  if (vertical_) {
80  strm << "rankdir = BT;\n";
81  } else {
82  strm << "rankdir = LR;\n";
83  }
84  strm << "size = \"" << width_ << "," << height_ << "\";\n";
85  if (!title_.empty()) strm << "label = \"" + title_ + "\";\n";
86  strm << "center = 1;\n";
87  if (portrait_) {
88  strm << "orientation = Portrait;\n";
89  } else {
90  strm << "orientation = Landscape;\n";
91  }
92  strm << "ranksep = \"" << ranksep_ << "\";\n"
93  << "nodesep = \"" << nodesep_ << "\";\n";
94  // Initial state first.
95  DrawState(strm, start);
96  for (StateIterator<Fst<Arc>> siter(fst_); !siter.Done(); siter.Next()) {
97  const auto s = siter.Value();
98  if (s != start) DrawState(strm, s);
99  }
100  strm << "}\n";
101  }
102 
103  private:
104  void SetStreamState(std::ostream &strm) const {
105  strm << std::setprecision(precision_);
106  if (float_format_ == "e") strm << std::scientific;
107  if (float_format_ == "f") strm << std::fixed;
108  // O.w. defaults to "g" per standard lib.
109  }
110 
111  // Escapes backslash and double quote if these occur in the string. Dot
112  // will not deal gracefully with these if they are not escaped.
113  static std::string Escape(std::string_view str) {
114  std::string ns;
115  for (char c : str) {
116  if (c == '\\' || c == '"') ns.push_back('\\');
117  ns.push_back(c);
118  }
119  return ns;
120  }
121 
122  std::string FormatId(StateId id, const SymbolTable *syms) const {
123  if (syms) {
124  auto symbol = syms->Find(id);
125  if (symbol.empty()) {
126  FSTERROR() << "FstDrawer: Integer " << id
127  << " is not mapped to any textual symbol"
128  << ", symbol table = " << syms->Name()
129  << ", destination = " << dest_;
130  symbol = "?";
131  }
132  return Escape(symbol);
133  } else {
134  return std::to_string(id);
135  }
136  }
137 
138  std::string FormatStateId(StateId s) const { return FormatId(s, ssyms_); }
139 
140  std::string FormatILabel(Label label) const {
141  return FormatId(label, isyms_);
142  }
143 
144  std::string FormatOLabel(Label label) const {
145  return FormatId(label, osyms_);
146  }
147 
148  std::string FormatWeight(Weight w) const {
149  std::stringstream ss;
150  SetStreamState(ss);
151  ss << w;
152  // Weight may have double quote characters in it, so escape it.
153  return Escape(ss.str());
154  }
155 
156  void DrawState(std::ostream &strm, StateId s) const {
157  strm << s << " [label = \"" << FormatStateId(s);
158  const auto weight = fst_.Final(s);
159  if (weight != Weight::Zero()) {
160  if (show_weight_one_ || (weight != Weight::One())) {
161  strm << "/" << FormatWeight(weight);
162  }
163  strm << "\", shape = doublecircle,";
164  } else {
165  strm << "\", shape = circle,";
166  }
167  if (s == fst_.Start()) {
168  strm << " style = bold,";
169  } else {
170  strm << " style = solid,";
171  }
172  strm << " fontsize = " << fontsize_ << "]\n";
173  for (ArcIterator<Fst<Arc>> aiter(fst_, s); !aiter.Done(); aiter.Next()) {
174  const auto &arc = aiter.Value();
175  strm << "\t" << s << " -> " << arc.nextstate << " [label = \""
176  << FormatILabel(arc.ilabel);
177  if (!accep_) {
178  strm << ":" << FormatOLabel(arc.olabel);
179  }
180  if (show_weight_one_ || (arc.weight != Weight::One())) {
181  strm << "/" << FormatWeight(arc.weight);
182  }
183  strm << "\", fontsize = " << fontsize_ << "];\n";
184  }
185  }
186 
187  const Fst<Arc> &fst_;
188  const SymbolTable *isyms_; // ilabel symbol table.
189  const SymbolTable *osyms_; // olabel symbol table.
190  const SymbolTable *ssyms_; // slabel symbol table.
191  bool accep_; // Print as acceptor when possible.
192  std::string dest_; // Drawn FST destination name.
193 
194  std::string title_;
195  float width_;
196  float height_;
197  bool portrait_;
198  bool vertical_;
199  float ranksep_;
200  float nodesep_;
201  int fontsize_;
202  int precision_;
203  std::string float_format_;
204  bool show_weight_one_;
205 
206  FstDrawer(const FstDrawer &) = delete;
207  FstDrawer &operator=(const FstDrawer &) = delete;
208 };
209 
210 } // namespace fst
211 
212 #endif // FST_SCRIPT_DRAW_IMPL_H_
const std::string & Name() const
Definition: symbol-table.h:466
typename Arc::Weight Weight
Definition: draw-impl.h:47
virtual Weight Final(StateId) const =0
constexpr int kNoStateId
Definition: fst.h:196
#define FSTERROR()
Definition: util.h:56
FstDrawer(const Fst< Arc > &fst, const SymbolTable *isyms, const SymbolTable *osyms, const SymbolTable *ssyms, bool accep, std::string_view title, float width, float height, bool portrait, bool vertical, float ranksep, float nodesep, int fontsize, int precision, std::string_view float_format, bool show_weight_one)
Definition: draw-impl.h:49
virtual StateId Start() const =0
typename Arc::StateId StateId
Definition: draw-impl.h:46
std::string Find(int64_t key) const
Definition: symbol-table.h:450
typename Arc::Label Label
Definition: draw-impl.h:45
void Draw(std::ostream &strm, std::string_view dest)
Definition: draw-impl.h:73
constexpr uint64_t kAcceptor
Definition: properties.h:64