tree-renderer.cc
Go to the documentation of this file.
1 // tree/tree-renderer.cc
2 
3 // Copyright 2012 Vassil Panayotov
4 
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
19 
20 #include "tree/tree-renderer.h"
21 
22 #include "tree/context-dep.h"
23 
24 namespace kaldi {
27 const std::string TreeRenderer::kEdgeColor = "black";
28 const std::string TreeRenderer::kEdgeColorQuery = "red";
29 
30 void
31 TreeRenderer::RenderNonLeaf(int32 id, const EventKeyType &key, bool in_query) {
32  std::string color = in_query? kEdgeColorQuery: kEdgeColor;
33  int32 width = in_query? kEdgeWidthQuery: kEdgeWidth;
34  std::string label;
35  if (key == kPdfClass) {
36  label = "\"PdfClass = ?\"";
37  } else if (key == 0) {
38  if (N_ == 1 && P_ == 0) // monophone tree?
39  label = "\"Phone = ?\"";
40  else if (N_ == 3 && P_ == 1) // triphone tree?
41  label = "\"LContext = ?\"";
42  } else if (key == 2 && N_ == 3 && P_ == 1) {
43  label = "\"RContext = ?\"";
44  } else if (key >= 0 && key <= N_-1) {
45  if (P_ == key)
46  label = "\"Center = ?\"";
47  else {
48  std::ostringstream oss;
49  oss << "\"Ctx Position " << key << " = ?\"";
50  label = oss.str();
51  }
52  } else {
53  KALDI_ERR << "Invalid decision tree key: " << key;
54  }
55 
56  out_ << id << "[label=" << label << ", color=" << color
57  << ", penwidth=" << width << "];" << std::endl;
58 }
59 
60 std::string
62  const ConstIntegerSet<EventValueType> &intset) {
63  std::ostringstream oss;
65  for (; child != intset.end(); ++child) {
66  if (child != intset.begin())
67  oss << ", ";
68  if (key != kPdfClass) {
69  std::string phone =
70  phone_syms_.Find(static_cast<kaldi::int64>(*child));
71  if (phone.empty())
72  KALDI_ERR << "No phone found for Phone ID " << *child;
73  oss << phone;
74  } else {
75  oss << *child;
76  }
77  }
78 
79  return oss.str();
80 }
81 
82 void TreeRenderer::RenderSplit(const EventType *query, int32 id) {
83  ExpectToken(is_, binary_, "SE");
84  EventKeyType key;
85  ReadBasicType(is_, binary_, &key);
87  yes_set.Read(is_, binary_);
88  ExpectToken(is_, binary_, "{");
89 
90  EventValueType value = -30000000; // just a value I guess is invalid
91  if (query != NULL)
92  EventMap::Lookup(*query, key, &value);
93  const EventType *query_yes = yes_set.count(value)? query: NULL;
94  const EventType *query_no = (query_yes == NULL)? query: NULL;
95  std::string color_yes = (query_yes)? kEdgeColorQuery: kEdgeColor;
96  std::string color_no = (query && !query_yes)? kEdgeColorQuery: kEdgeColor;
97  int32 width_yes = (query_yes)? kEdgeWidthQuery: kEdgeWidth;
98  int32 width_no = (query && !query_yes)? kEdgeWidthQuery: kEdgeWidth;
99  RenderNonLeaf(id, key, (query != NULL)); // Draw the node itself
100  std::string yes_label = MakeEdgeLabel(key, yes_set);
101  out_ << "\t" << id << " -> " << next_id_++ << " ["; // YES edge
102  if (use_tooltips_) {
103  out_ << "tooltip=\"" << yes_label << "\", label=YES"
104  << ", penwidth=" << width_yes << ", color=" << color_yes << "];\n";
105  } else {
106  out_ << "label=\"" << yes_label << "\", penwidth=" << width_yes
107  << ", penwidth=" << width_yes << ", color=" << color_yes << "];\n";
108  }
109  RenderSubTree(query_yes, next_id_-1); // Render YES subtree
110  out_ << "\t" << id << " -> " << next_id_++ << "[label=NO" // NO edge
111  << ", color=" << color_no << ", penwidth=" << width_no << "];\n";
112  RenderSubTree(query_no, next_id_-1); // Render NO subtree
113 
114  ExpectToken(is_, binary_, "}");
115 }
116 
117 void TreeRenderer::RenderTable(const EventType *query, int32 id) {
118  ExpectToken(is_, binary_, "TE");
119  EventKeyType key;
120  ReadBasicType(is_, binary_, &key);
121  uint32 size;
122  ReadBasicType(is_, binary_, &size);
123  ExpectToken(is_, binary_, "(");
124 
125  EventValueType value = -3000000; // just a value I hope is invalid
126  if (query != NULL)
127  EventMap::Lookup(*query, key, &value);
128  RenderNonLeaf(id, key, (query != NULL));
129  for (size_t t = 0; t < size; t++) {
130  std::string color = (t == value)? kEdgeColorQuery: kEdgeColor;
131  int32 width = (t==value)? kEdgeWidthQuery: kEdgeWidth;
132  std::ostringstream label;
133  if (key == kPdfClass) {
134  label << t;
135  } else if (key >= 0 && key < N_) {
136  if (t == 0) {
137  ExpectToken(is_, binary_, "NULL"); // consume the invalid/NULL entry
138  continue;
139  }
140  std::string phone = phone_syms_.Find(static_cast<kaldi::int64>(t));
141  if (phone.empty())
142  KALDI_ERR << "Phone ID found in a TableEventMap, but not in the "
143  << "phone symbol table! ID: " << t;
144  label << phone;
145  } else {
146  KALDI_ERR << "TableEventMap: Invalid event key: " << key;
147  }
148  // draw the edge to the child subtree
149  out_ << "\t" << id << " -> " << next_id_++ << " [label=" << label.str()
150  << ", color=" << color << ", penwidth=" << width << "];\n";
151  const EventType *query_child = (t == value)? query: NULL;
152  RenderSubTree(query_child, next_id_-1); // render the child subtree
153  }
154 
155  ExpectToken(is_, binary_, ")");
156 }
157 
159  ExpectToken(is_, binary_, "CE");
160  EventAnswerType answer;
161  ReadBasicType(is_, binary_, &answer);
162 
163  std::string color = (query!=NULL)? kEdgeColorQuery: kEdgeColor;
164  int32 width = (query!=NULL)? kEdgeWidthQuery: kEdgeWidth;
165  out_ << id << "[shape=doublecircle, label=" << answer
166  << ",color=" << color << ", penwidth=" << width << "];\n";
167 }
168 
170  char c = Peek(is_, binary_);
171  if (c == 'N') {
172  ExpectToken(is_, binary_, "NULL"); // consume NULL entries
173  return;
174  } else if (c == 'C') {
175  RenderConstant(query, id);
176  } else if (c == 'T') {
177  RenderTable(query, id);
178  } else if (c == 'S') {
179  RenderSplit(query, id);
180  } else {
181  KALDI_ERR << "EventMap::read, was not expecting character " << CharToString(c)
182  << ", at file position " << is_.tellg();
183  }
184 }
185 
186 void TreeRenderer::Render(const EventType *query = 0) {
187  ExpectToken(is_, binary_, "ContextDependency");
190  ExpectToken(is_, binary_, "ToPdf");
191  if (query && query->size() != N_+1)
192  KALDI_ERR << "Invalid query size \"" << query->size() << "\"! Expected \""
193  << N_+1 << '"';
194  out_ << "digraph EventMap {\n";
195  RenderSubTree(query, next_id_++);
196  out_ << "}\n";
197  ExpectToken(is_, binary_, "EndContextDependency");
198 }
199 
200 } // namespace kaldi
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
fst::SymbolTable & phone_syms_
Definition: tree-renderer.h:72
void ReadBasicType(std::istream &is, bool binary, T *t)
ReadBasicType is the name of the read function for bool, integer types, and floating-point types...
Definition: io-funcs-inl.h:55
kaldi::int32 int32
void RenderSplit(const EventType *query, int32 id)
int Peek(std::istream &is, bool binary)
Peek consumes whitespace (if binary == false) and then returns the peek() value of the stream...
Definition: io-funcs.cc:145
std::ostream & out_
Definition: tree-renderer.h:74
static const EventKeyType kPdfClass
Definition: context-dep.h:39
std::vector< std::pair< EventKeyType, EventValueType > > EventType
Definition: event-map.h:58
void ExpectToken(std::istream &is, bool binary, const char *token)
ExpectToken tries to read in the given token, and throws an exception on failure. ...
Definition: io-funcs.cc:191
int32 EventKeyType
Things of type EventKeyType can take any value.
Definition: event-map.h:45
#define KALDI_ERR
Definition: kaldi-error.h:147
std::istream & is_
Definition: tree-renderer.h:73
void RenderConstant(const EventType *query, int32 id)
std::string CharToString(const char &c)
Definition: kaldi-utils.cc:36
void Read(std::istream &is, bool binary)
static const int32 kEdgeWidth
Definition: tree-renderer.h:33
static bool Lookup(const EventType &event, EventKeyType key, EventValueType *ans)
Definition: event-map.cc:290
void RenderNonLeaf(int32 id, const EventKeyType &key, bool in_query)
void RenderSubTree(const EventType *query, int32 id)
iterator begin() const
std::string MakeEdgeLabel(const EventKeyType &key, const ConstIntegerSet< EventValueType > &intset)
static const std::string kEdgeColorQuery
Definition: tree-renderer.h:36
static const int32 kEdgeWidthQuery
Definition: tree-renderer.h:34
void RenderTable(const EventType *query, int32 id)
static const std::string kEdgeColor
Definition: tree-renderer.h:35
int32 EventAnswerType
As far as the event-map code itself is concerned, things of type EventAnswerType may take any value e...
Definition: event-map.h:56
int32 EventValueType
Given current code, things of type EventValueType should generally be nonnegative and in a reasonably...
Definition: event-map.h:51
void Render(const EventType *query)