lattice-weight.h
Go to the documentation of this file.
1 // fstext/lattice-weight.h
2 // Copyright 2009-2012 Microsoft Corporation
3 // Johns Hopkins University (author: Daniel Povey)
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 
21 #ifndef KALDI_FSTEXT_LATTICE_WEIGHT_H_
22 #define KALDI_FSTEXT_LATTICE_WEIGHT_H_
23 
24 #include "fst/fstlib.h"
25 #include "base/kaldi-common.h"
26 
27 namespace fst {
28 
29 // Declare weight type for lattice... will import to namespace kaldi. has two
30 // members, value1_ and value2_, of type BaseFloat (normally equals float). It
31 // is basically the same as the tropical semiring on value1_+value2_, except it
32 // keeps track of a and b separately. More precisely, it is equivalent to the
33 // lexicographic semiring on (value1_+value2_), (value1_-value2_)
34 
35 
36 template<class FloatType>
38 
39 template <class FloatType>
40 inline std::ostream &operator <<(std::ostream &strm, const LatticeWeightTpl<FloatType> &w);
41 
42 template <class FloatType>
43 inline std::istream &operator >>(std::istream &strm, LatticeWeightTpl<FloatType> &w);
44 
45 
46 template<class FloatType>
47 class LatticeWeightTpl {
48  public:
49  typedef FloatType T; // normally float.
51 
52  inline T Value1() const { return value1_; }
53 
54  inline T Value2() const { return value2_; }
55 
56  inline void SetValue1(T f) { value1_ = f; }
57 
58  inline void SetValue2(T f) { value2_ = f; }
59 
61 
62  LatticeWeightTpl(T a, T b): value1_(a), value2_(b) {}
63 
64  LatticeWeightTpl(const LatticeWeightTpl &other): value1_(other.value1_), value2_(other.value2_) { }
65 
67  value1_ = w.value1_;
68  value2_ = w.value2_;
69  return *this;
70  }
71 
73  return *this;
74  }
75 
76  static const LatticeWeightTpl Zero() {
77  return LatticeWeightTpl(std::numeric_limits<T>::infinity(),
78  std::numeric_limits<T>::infinity());
79  }
80 
81  static const LatticeWeightTpl One() {
82  return LatticeWeightTpl(0.0, 0.0);
83  }
84 
85  static const std::string &Type() {
86  static const std::string type = (sizeof(T) == 4 ? "lattice4" : "lattice8") ;
87  return type;
88  }
89 
90  static const LatticeWeightTpl NoWeight() {
91  return LatticeWeightTpl(std::numeric_limits<FloatType>::quiet_NaN(),
92  std::numeric_limits<FloatType>::quiet_NaN());
93  }
94 
95  bool Member() const {
96  // value1_ == value1_ tests for NaN.
97  // also test for no -inf, and either both or neither
98  // must be +inf, and
99  if (value1_ != value1_ || value2_ != value2_) return false; // NaN
100  if (value1_ == -std::numeric_limits<T>::infinity() ||
101  value2_ == -std::numeric_limits<T>::infinity()) return false; // -infty not allowed
102  if (value1_ == std::numeric_limits<T>::infinity() ||
103  value2_ == std::numeric_limits<T>::infinity()) {
104  if (value1_ != std::numeric_limits<T>::infinity() ||
105  value2_ != std::numeric_limits<T>::infinity()) return false; // both must be +infty;
106  // this is necessary so that the semiring has only one zero.
107  }
108  return true;
109  }
110 
111  LatticeWeightTpl Quantize(float delta = kDelta) const {
112  if (value1_ + value2_ == -std::numeric_limits<T>::infinity()) {
113  return LatticeWeightTpl(-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
114  } else if (value1_ + value2_ == std::numeric_limits<T>::infinity()) {
115  return LatticeWeightTpl(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
116  } else if (value1_ + value2_ != value1_ + value2_) { // NaN
118  } else {
119  return LatticeWeightTpl(floor(value1_/delta + 0.5F)*delta, floor(value2_/delta + 0.5F) * delta);
120  }
121  }
122  static constexpr uint64 Properties() {
123  return kLeftSemiring | kRightSemiring | kCommutative |
124  kPath | kIdempotent;
125  }
126 
127  // This is used in OpenFst for binary I/O. This is OpenFst-style,
128  // not Kaldi-style, I/O.
129  std::istream &Read(std::istream &strm) {
130  // Always read/write as float, even if T is double,
131  // so we can use OpenFst-style read/write and still maintain
132  // compatibility when compiling with different FloatTypes
133  ReadType(strm, &value1_);
134  ReadType(strm, &value2_);
135  return strm;
136  }
137 
138 
139  // This is used in OpenFst for binary I/O. This is OpenFst-style,
140  // not Kaldi-style, I/O.
141  std::ostream &Write(std::ostream &strm) const {
142  WriteType(strm, value1_);
143  WriteType(strm, value2_);
144  return strm;
145  }
146 
147  size_t Hash() const {
148  size_t ans;
149  union {
150  T f;
151  size_t s;
152  } u;
153  u.s = 0;
154  u.f = value1_;
155  ans = u.s;
156  u.f = value2_;
157  ans += u.s;
158  return ans;
159  }
160 
161  protected:
162  inline static void WriteFloatType(std::ostream &strm, const T &f) {
163  if (f == std::numeric_limits<T>::infinity())
164  strm << "Infinity";
165  else if (f == -std::numeric_limits<T>::infinity())
166  strm << "-Infinity";
167  else if (f != f)
168  strm << "BadNumber";
169  else
170  strm << f;
171  }
172 
173  // Internal helper function, used in ReadNoParen.
174  inline static void ReadFloatType(std::istream &strm, T &f) {
175  std::string s;
176  strm >> s;
177  if (s == "Infinity") {
178  f = std::numeric_limits<T>::infinity();
179  } else if (s == "-Infinity") {
180  f = -std::numeric_limits<T>::infinity();
181  } else if (s == "BadNumber") {
182  f = std::numeric_limits<T>::quiet_NaN();
183  } else {
184  char *p;
185  f = strtod(s.c_str(), &p);
186  if (p < s.c_str() + s.size())
187  strm.clear(std::ios::badbit);
188  }
189  }
190 
191  // Reads LatticeWeight when there are no parentheses around pair terms...
192  // currently the only form supported.
193  inline std::istream &ReadNoParen(
194  std::istream &strm, char separator) {
195  int c;
196  do {
197  c = strm.get();
198  } while (isspace(c));
199 
200  std::string s1;
201  while (c != separator) {
202  if (c == EOF) {
203  strm.clear(std::ios::badbit);
204  return strm;
205  }
206  s1 += c;
207  c = strm.get();
208  }
209  std::istringstream strm1(s1);
210  ReadFloatType(strm1, value1_); // ReadFloatType is class member function
211  // read second element
212  ReadFloatType(strm, value2_);
213  return strm;
214  }
215 
216  friend std::istream &operator>> <FloatType>(std::istream&, LatticeWeightTpl<FloatType>&);
217  friend std::ostream &operator<< <FloatType>(std::ostream&, const LatticeWeightTpl<FloatType>&);
218 
219  private:
222 
223 
224 };
225 
226 
227 /* ScaleTupleWeight is a function defined for LatticeWeightTpl and
228  CompactLatticeWeightTpl that mutliplies the pair (value1_, value2_) by a 2x2
229  matrix. Used, for example, in applying acoustic scaling.
230  */
231 template<class FloatType, class ScaleFloatType>
234  const std::vector<std::vector<ScaleFloatType> > &scale) {
235  // Without the next special case we'd get NaNs from infinity * 0
236  if (w.Value1() == std::numeric_limits<FloatType>::infinity())
238  return LatticeWeightTpl<FloatType>(scale[0][0] * w.Value1() + scale[0][1] * w.Value2(),
239  scale[1][0] * w.Value1() + scale[1][1] * w.Value2());
240 }
241 
242 /* For testing purposes and in case it's ever useful, we define a similar
243  function to apply to LexicographicWeight and the like, templated on
244  TropicalWeight<float> etc.; we use PairWeight which is the base class of
245  LexicographicWeight.
246 */
247 template<class FloatType, class ScaleFloatType>
248 inline PairWeight<TropicalWeightTpl<FloatType>,
249  TropicalWeightTpl<FloatType> > ScaleTupleWeight(
250  const PairWeight<TropicalWeightTpl<FloatType>,
251  TropicalWeightTpl<FloatType> > &w,
252  const std::vector<std::vector<ScaleFloatType> > &scale) {
253  typedef TropicalWeightTpl<FloatType> BaseType;
254  typedef PairWeight<BaseType, BaseType> PairType;
255  const BaseType zero = BaseType::Zero();
256  // Without the next special case we'd get NaNs from infinity * 0
257  if (w.Value1() == zero || w.Value2() == zero)
258  return PairType(zero, zero);
259  FloatType f1 = w.Value1().Value(), f2 = w.Value2().Value();
260  return PairType(BaseType(scale[0][0] * f1 + scale[0][1] * f2),
261  BaseType(scale[1][0] * f1 + scale[1][1] * f2));
262 }
263 
264 
265 
266 template<class FloatType>
268  const LatticeWeightTpl<FloatType> &wb) {
269  // Volatile qualifier thwarts over-aggressive compiler optimizations
270  // that lead to problems esp. with NaturalLess().
271  volatile FloatType va1 = wa.Value1(), va2 = wa.Value2(),
272  vb1 = wb.Value1(), vb2 = wb.Value2();
273  return (va1 == vb1 && va2 == vb2);
274 }
275 
276 template<class FloatType>
278  const LatticeWeightTpl<FloatType> &wb) {
279  // Volatile qualifier thwarts over-aggressive compiler optimizations
280  // that lead to problems esp. with NaturalLess().
281  volatile FloatType va1 = wa.Value1(), va2 = wa.Value2(),
282  vb1 = wb.Value1(), vb2 = wb.Value2();
283  return (va1 != vb1 || va2 != vb2);
284 }
285 
286 
287 // We define a Compare function LatticeWeightTpl even though it's
288 // not required by the semiring standard-- it's just more efficient
289 // to do it this way rather than using the NaturalLess template.
290 
292 
293 template<class FloatType>
294 inline int Compare (const LatticeWeightTpl<FloatType> &w1,
295  const LatticeWeightTpl<FloatType> &w2) {
296  FloatType f1 = w1.Value1() + w1.Value2(),
297  f2 = w2.Value1() + w2.Value2();
298  if (f1 < f2) { return 1; } // having smaller cost means you're larger
299  // in the semiring [higher probability]
300  else if (f1 > f2) { return -1; }
301  // mathematically we should be comparing (w1.value1_-w1.value2_ < w2.value1_-w2.value2_)
302  // in the next line, but add w1.value1_+w1.value2_ = w2.value1_+w2.value2_ to both sides and
303  // divide by two, and we get the simpler equivalent form w1.value1_ < w2.value1_.
304  else if (w1.Value1() < w2.Value1()) { return 1; }
305  else if (w1.Value1() > w2.Value1()) { return -1; }
306  else { return 0; }
307 }
308 
309 
310 template<class FloatType>
312  const LatticeWeightTpl<FloatType> &w2) {
313  return (Compare(w1, w2) >= 0 ? w1 : w2);
314 }
315 
316 
317 // For efficiency, override the NaturalLess template class.
318 template<class FloatType>
319 class NaturalLess<LatticeWeightTpl<FloatType> > {
320  public:
322 
324 
325  bool operator()(const Weight &w1, const Weight &w2) const {
326  // NaturalLess is a negative order (opposite to normal ordering).
327  // This operator () corresponds to "<" in the negative order, which
328  // corresponds to the ">" in the normal order.
329  return (Compare(w1, w2) == 1);
330  }
331 };
332 template<>
333 class NaturalLess<LatticeWeightTpl<float> > {
334  public:
336 
338 
339  bool operator()(const Weight &w1, const Weight &w2) const {
340  // NaturalLess is a negative order (opposite to normal ordering).
341  // This operator () corresponds to "<" in the negative order, which
342  // corresponds to the ">" in the normal order.
343  return (Compare(w1, w2) == 1);
344  }
345 };
346 template<>
347 class NaturalLess<LatticeWeightTpl<double> > {
348  public:
350 
352 
353  bool operator()(const Weight &w1, const Weight &w2) const {
354  // NaturalLess is a negative order (opposite to normal ordering).
355  // This operator () corresponds to "<" in the negative order, which
356  // corresponds to the ">" in the normal order.
357  return (Compare(w1, w2) == 1);
358  }
359 };
360 
361 template<class FloatType>
363  const LatticeWeightTpl<FloatType> &w2) {
364  return LatticeWeightTpl<FloatType>(w1.Value1()+w2.Value1(), w1.Value2()+w2.Value2());
365 }
366 
367 // divide w1 by w2 (on left/right/any doesn't matter as
368 // commutative).
369 template<class FloatType>
371  const LatticeWeightTpl<FloatType> &w2,
372  DivideType typ = DIVIDE_ANY) {
373  typedef FloatType T;
374  T a = w1.Value1() - w2.Value1(), b = w1.Value2() - w2.Value2();
375  if (a != a || b != b || a == -std::numeric_limits<T>::infinity()
376  || b == -std::numeric_limits<T>::infinity()) {
377  KALDI_WARN << "LatticeWeightTpl::Divide, NaN or invalid number produced. "
378  << "[dividing by zero?] Returning zero";
379  return LatticeWeightTpl<T>::Zero();
380  }
381  if (a == std::numeric_limits<T>::infinity() ||
382  b == std::numeric_limits<T>::infinity())
383  return LatticeWeightTpl<T>::Zero(); // not a valid number if only one is infinite.
384  return LatticeWeightTpl<T>(a, b);
385 }
386 
387 
388 template<class FloatType>
390  const LatticeWeightTpl<FloatType> &w2,
391  float delta = kDelta) {
392  if (w1.Value1() == w2.Value1() && w1.Value2() == w2.Value2()) return true; // handles Zero().
393  return (fabs((w1.Value1() + w1.Value2()) - (w2.Value1() + w2.Value2())) <= delta);
394 }
395 
396 template <class FloatType>
397 inline std::ostream &operator <<(std::ostream &strm, const LatticeWeightTpl<FloatType> &w) {
399  CHECK(FLAGS_fst_weight_separator.size() == 1);
400  strm << FLAGS_fst_weight_separator[0]; // comma by default;
401  // may or may not be settable from Kaldi programs.
403  return strm;
404 }
405 
406 template <class FloatType>
407 inline std::istream &operator >>(std::istream &strm, LatticeWeightTpl<FloatType> &w1) {
408  CHECK(FLAGS_fst_weight_separator.size() == 1);
409  // separator defaults to ','
410  return w1.ReadNoParen(strm, FLAGS_fst_weight_separator[0]);
411 }
412 
413 
414 
415 // CompactLattice will be an acceptor (accepting the words/output-symbols),
416 // with the weights and input-symbol-seqs on the arcs.
417 // There must be a total order on W. We assume for the sake of efficiency
418 // that there is a function
419 // Compare(W w1, W w2) that returns -1 if w1 < w2, +1 if w1 > w2, and
420 // zero if w1 == w2, and Plus for type W returns (Compare(w1,w2) >= 0 ? w1 : w2).
421 
422 template<class WeightType, class IntType>
424  public:
425  typedef WeightType W;
426 
428 
429  // Plus is like LexicographicWeight on the pair (weight_, string_), but where we
430  // use standard lexicographic order on string_ [this is not the same as
431  // NaturalLess on the StringWeight equivalent, which does not define a
432  // total order].
433  // Times, Divide obvious... (support both left & right division..)
434  // CommonDivisor would need to be coded separately.
435 
437 
438  CompactLatticeWeightTpl(const WeightType &w, const std::vector<IntType> &s):
439  weight_(w), string_(s) { }
440 
442  weight_ = w.weight_;
443  string_ = w.string_;
444  return *this;
445  }
446 
447  const W &Weight() const { return weight_; }
448 
449  const std::vector<IntType> &String() const { return string_; }
450 
451  void SetWeight(const W &w) { weight_ = w; }
452 
453  void SetString(const std::vector<IntType> &s) { string_ = s; }
454 
457  WeightType::Zero(), std::vector<IntType>());
458  }
459 
462  WeightType::One(), std::vector<IntType>());
463  }
464 
465  inline static std::string GetIntSizeString() {
466  char buf[2];
467  buf[0] = '0' + sizeof(IntType);
468  buf[1] = '\0';
469  return buf;
470  }
471  static const std::string &Type() {
472  static const std::string type = "compact" + WeightType::Type()
473  + GetIntSizeString();
474  return type;
475  }
476 
479  WeightType::NoWeight(), std::vector<IntType>());
480  }
481 
482 
484  size_t s = string_.size();
485  std::vector<IntType> v(s);
486  for(size_t i = 0; i < s; i++)
487  v[i] = string_[s-i-1];
489  }
490 
491  bool Member() const {
492  // a semiring has only one zero, this is the important property
493  // we're trying to maintain here. So force string_ to be empty if
494  // w_ == zero.
495  if (!weight_.Member()) return false;
496  if (weight_ == WeightType::Zero())
497  return string_.empty();
498  else
499  return true;
500  }
501 
502  CompactLatticeWeightTpl Quantize(float delta = kDelta) const {
503  return CompactLatticeWeightTpl(weight_.Quantize(delta), string_);
504  }
505 
506  static constexpr uint64 Properties() {
507  return kLeftSemiring | kRightSemiring | kPath | kIdempotent;
508  }
509 
510  // This is used in OpenFst for binary I/O. This is OpenFst-style,
511  // not Kaldi-style, I/O.
512  std::istream &Read(std::istream &strm) {
513  weight_.Read(strm);
514  if (strm.fail()){ return strm; }
515  int32 sz;
516  ReadType(strm, &sz);
517  if (strm.fail()){ return strm; }
518  if (sz < 0) {
519  KALDI_WARN << "Negative string size! Read failure";
520  strm.clear(std::ios::badbit);
521  return strm;
522  }
523  string_.resize(sz);
524  for(int32 i = 0; i < sz; i++) {
525  ReadType(strm, &(string_[i]));
526  }
527  return strm;
528  }
529 
530  // This is used in OpenFst for binary I/O. This is OpenFst-style,
531  // not Kaldi-style, I/O.
532  std::ostream &Write(std::ostream &strm) const {
533  weight_.Write(strm);
534  if (strm.fail()){ return strm; }
535  int32 sz = static_cast<int32>(string_.size());
536  WriteType(strm, sz);
537  for(int32 i = 0; i < sz; i++)
538  WriteType(strm, string_[i]);
539  return strm;
540  }
541  size_t Hash() const {
542  size_t ans = weight_.Hash();
543  // any weird numbers here are largish primes
544  size_t sz = string_.size(), mult = 6967;
545  for(size_t i = 0; i < sz; i++) {
546  ans += string_[i] * mult;
547  mult *= 7499;
548  }
549  return ans;
550  }
551  private:
553  std::vector<IntType> string_;
554 
555 };
556 
557 template<class WeightType, class IntType>
560  return (w1.Weight() == w2.Weight() && w1.String() == w2.String());
561 }
562 
563 template<class WeightType, class IntType>
566  return (w1.Weight() != w2.Weight() || w1.String() != w2.String());
567 }
568 
569 template<class WeightType, class IntType>
572  float delta = kDelta) {
573  return (ApproxEqual(w1.Weight(), w2.Weight(), delta) && w1.String() == w2.String());
574 }
575 
576 
577 
578 // Compare is not part of the standard for weight types, but used internally for
579 // efficiency. The comparison here first compares the weight; if this is the
580 // same, it compares the string. The comparison on strings is: first compare
581 // the length, if this is the same, use lexicographical order. We can't just
582 // use the lexicographical order because this would destroy the distributive
583 // property of multiplication over addition, taking into account that addition
584 // uses Compare. The string element of "Compare" isn't super-important in
585 // practical terms; it's only needed to ensure that Plus always give consistent
586 // answers and is symmetric. It's essentially for tie-breaking, but we need to
587 // make sure all the semiring axioms are satisfied otherwise OpenFst might
588 // break.
589 
590 template<class WeightType, class IntType>
593  int c1 = Compare(w1.Weight(), w2.Weight());
594  if (c1 != 0) return c1;
595  int l1 = w1.String().size(), l2 = w2.String().size();
596  // Use opposite order on the string lengths, so that if the costs are the same,
597  // the shorter string wins.
598  if (l1 > l2) return -1;
599  else if (l1 < l2) return 1;
600  for(int i = 0; i < l1; i++) {
601  if (w1.String()[i] < w2.String()[i]) return -1;
602  else if (w1.String()[i] > w2.String()[i]) return 1;
603  }
604  return 0;
605 }
606 
607 // For efficiency, override the NaturalLess template class.
608 template<class FloatType, class IntType>
609 class NaturalLess<CompactLatticeWeightTpl<LatticeWeightTpl<FloatType>, IntType> > {
610  public:
612 
614 
615  bool operator()(const Weight &w1, const Weight &w2) const {
616  // NaturalLess is a negative order (opposite to normal ordering).
617  // This operator () corresponds to "<" in the negative order, which
618  // corresponds to the ">" in the normal order.
619  return (Compare(w1, w2) == 1);
620  }
621 };
622 template<>
624  public:
626 
628 
629  bool operator()(const Weight &w1, const Weight &w2) const {
630  // NaturalLess is a negative order (opposite to normal ordering).
631  // This operator () corresponds to "<" in the negative order, which
632  // corresponds to the ">" in the normal order.
633  return (Compare(w1, w2) == 1);
634  }
635 };
636 template<>
637 class NaturalLess<CompactLatticeWeightTpl<LatticeWeightTpl<double>, int32> > {
638  public:
640 
642 
643  bool operator()(const Weight &w1, const Weight &w2) const {
644  // NaturalLess is a negative order (opposite to normal ordering).
645  // This operator () corresponds to "<" in the negative order, which
646  // corresponds to the ">" in the normal order.
647  return (Compare(w1, w2) == 1);
648  }
649 };
650 
651 // Make sure Compare is defined for TropicalWeight, so everything works
652 // if we substitute LatticeWeight for TropicalWeight.
653 inline int Compare(const TropicalWeight &w1,
654  const TropicalWeight &w2) {
655  float f1 = w1.Value(), f2 = w2.Value();
656  if (f1 == f2) return 0;
657  else if (f1 > f2) return -1;
658  else return 1;
659 }
660 
661 
662 
663 template<class WeightType, class IntType>
667  return (Compare(w1, w2) >= 0 ? w1 : w2);
668 }
669 
670 template<class WeightType, class IntType>
674  WeightType w = Times(w1.Weight(), w2.Weight());
675  if (w == WeightType::Zero()) {
677  // special case to ensure zero is unique
678  } else {
679  std::vector<IntType> v;
680  v.resize(w1.String().size() + w2.String().size());
681  typename std::vector<IntType>::iterator iter = v.begin();
682  iter = std::copy(w1.String().begin(), w1.String().end(), iter); // returns end of first range.
683  std::copy(w2.String().begin(), w2.String().end(), iter);
685  }
686 }
687 
688 template<class WeightType, class IntType>
691  DivideType div = DIVIDE_ANY) {
692  if (w1.Weight() == WeightType::Zero()) {
693  if (w2.Weight() != WeightType::Zero()) {
695  } else {
696  KALDI_ERR << "Division by zero [0/0]";
697  }
698  } else if (w2.Weight() == WeightType::Zero()) {
699  KALDI_ERR << "Error: division by zero";
700  }
701  WeightType w = Divide(w1.Weight(), w2.Weight());
702 
703  const std::vector<IntType> v1 = w1.String(), v2 = w2.String();
704  if (v2.size() > v1.size()) {
705  KALDI_ERR << "Cannot divide, length mismatch";
706  }
707  typename std::vector<IntType>::const_iterator v1b = v1.begin(),
708  v1e = v1.end(), v2b = v2.begin(), v2e = v2.end();
709  if (div == DIVIDE_LEFT) {
710  if (!std::equal(v2b, v2e, v1b)) { // v2 must be identical to first part of v1.
711  KALDI_ERR << "Cannot divide, data mismatch";
712  }
714  w, std::vector<IntType>(v1b+(v2e-v2b), v1e)); // return last part of v1.
715  } else if (div == DIVIDE_RIGHT) {
716  if (!std::equal(v2b, v2e, v1e-(v2e-v2b))) { // v2 must be identical to last part of v1.
717  KALDI_ERR << "Cannot divide, data mismatch";
718  }
720  w, std::vector<IntType>(v1b, v1e-(v2e-v2b))); // return first part of v1.
721 
722  } else {
723  KALDI_ERR << "Cannot divide CompactLatticeWeightTpl with DIVIDE_ANY";
724  }
725  return CompactLatticeWeightTpl<WeightType,IntType>::Zero(); // keep compiler happy.
726 }
727 
728 template <class WeightType, class IntType>
729 inline std::ostream &operator <<(std::ostream &strm, const CompactLatticeWeightTpl<WeightType, IntType> &w) {
730  strm << w.Weight();
731  CHECK(FLAGS_fst_weight_separator.size() == 1);
732  strm << FLAGS_fst_weight_separator[0]; // comma by default.
733  for(size_t i = 0; i < w.String().size(); i++) {
734  strm << w.String()[i];
735  if (i+1 < w.String().size())
736  strm << kStringSeparator; // '_'; defined in string-weight.h in OpenFst code.
737  }
738  return strm;
739 }
740 
741 template <class WeightType, class IntType>
742 inline std::istream &operator >>(std::istream &strm, CompactLatticeWeightTpl<WeightType, IntType> &w) {
743  std::string s;
744  strm >> s;
745  if (strm.fail()) {
746  return strm;
747  }
748  CHECK(FLAGS_fst_weight_separator.size() == 1);
749  size_t pos = s.find_last_of(FLAGS_fst_weight_separator); // normally ","
750  if (pos == std::string::npos) {
751  strm.clear(std::ios::badbit);
752  return strm;
753  }
754  // get parts of str before and after the separator (default: ',');
755  std::string s1(s, 0, pos), s2(s, pos+1);
756  std::istringstream strm1(s1);
757  WeightType weight;
758  strm1 >> weight;
759  w.SetWeight(weight);
760  if (strm1.fail() || !strm1.eof()) {
761  strm.clear(std::ios::badbit);
762  return strm;
763  }
764  // read string part.
765  std::vector<IntType> string;
766  const char *c = s2.c_str();
767  while(*c != '\0') {
768  if (*c == kStringSeparator) // '_'
769  c++;
770  char *c2;
771  long int i = strtol(c, &c2, 10);
772  if (c2 == c || static_cast<long int>(static_cast<IntType>(i)) != i) {
773  strm.clear(std::ios::badbit);
774  return strm;
775  }
776  c = c2;
777  string.push_back(static_cast<IntType>(i));
778  }
779  w.SetString(string);
780  return strm;
781 }
782 
783 template<class BaseWeightType, class IntType>
785  public:
787 
788  Weight operator()(const Weight &w1, const Weight &w2) const {
789  // First find longest common prefix of the strings.
790  typename std::vector<IntType>::const_iterator s1b = w1.String().begin(),
791  s1e = w1.String().end(), s2b = w2.String().begin(), s2e = w2.String().end();
792  while (s1b < s1e && s2b < s2e && *s1b == *s2b) {
793  s1b++;
794  s2b++;
795  }
796  return Weight(Plus(w1.Weight(), w2.Weight()), std::vector<IntType>(w1.String().begin(), s1b));
797  }
798 };
799 
807 template<class Weight, class IntType, class ScaleFloatType>
810  const std::vector<std::vector<ScaleFloatType> > &scale) {
812  Weight(ScaleTupleWeight(w.Weight(), scale)), w.String());
813 }
814 
818 template<class Float1, class Float2>
820  const LatticeWeightTpl<Float1> &w_in,
821  LatticeWeightTpl<Float2> *w_out) {
822  w_out->SetValue1(w_in.Value1());
823  w_out->SetValue2(w_in.Value2());
824 }
825 
826 template<class Float1, class Float2, class Int>
830  LatticeWeightTpl<Float2> weight2(w_in.Weight().Value1(),
831  w_in.Weight().Value2());
832  w_out->SetWeight(weight2);
833  w_out->SetString(w_in.String());
834 }
835 
836 // to convert from Lattice to standard FST
837 template<class Float1, class Float2>
839  const LatticeWeightTpl<Float1> &w_in,
840  TropicalWeightTpl<Float2> *w_out) {
841  TropicalWeightTpl<Float2> w1(w_in.Value1());
842  TropicalWeightTpl<Float2> w2(w_in.Value2());
843  *w_out = Times(w1, w2);
844 }
845 
846 template<class Float>
847 inline double ConvertToCost(const LatticeWeightTpl<Float> &w) {
848  return static_cast<double>(w.Value1()) + static_cast<double>(w.Value2());
849 }
850 
851 template<class Float, class Int>
853  return static_cast<double>(w.Weight().Value1()) + static_cast<double>(w.Weight().Value2());
854 }
855 
856 template<class Float>
857 inline double ConvertToCost(const TropicalWeightTpl<Float> &w) {
858  return w.Value();
859 }
860 
861 
862 } // namespace fst
863 
864 #endif // KALDI_FSTEXT_LATTICE_WEIGHT_H_
LatticeWeightTpl Quantize(float delta=kDelta) const
LatticeWeightTpl< FloatType > Divide(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2, DivideType typ=DIVIDE_ANY)
static constexpr uint64 Properties()
static const LatticeWeightTpl NoWeight()
LatticeWeightTpl< FloatType > ScaleTupleWeight(const LatticeWeightTpl< FloatType > &w, const std::vector< std::vector< ScaleFloatType > > &scale)
bool operator!=(const LatticeWeightTpl< FloatType > &wa, const LatticeWeightTpl< FloatType > &wb)
LatticeWeightTpl< FloatType > Reverse() const
static const std::string & Type()
static const LatticeWeightTpl One()
static void WriteFloatType(std::ostream &strm, const T &f)
CompactLatticeWeightTpl< LatticeWeightTpl< double >, int32 > Weight
For an extended explanation of the framework of which grammar-fsts are a part, please see Support for...
Definition: graph.dox:21
std::istream & Read(std::istream &strm)
CompactLatticeWeightTpl(const WeightType &w, const std::vector< IntType > &s)
LatticeWeightTpl & operator=(const LatticeWeightTpl &w)
bool operator()(const Weight &w1, const Weight &w2) const
bool operator()(const Weight &w1, const Weight &w2) const
CompactLatticeWeightTpl< WeightType, IntType > ReverseWeight
LatticeWeightTpl< FloatType > Plus(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
CompactLatticeWeightTpl< WeightType, IntType > Reverse() const
LatticeWeightTpl(const LatticeWeightTpl &other)
static std::string GetIntSizeString()
kaldi::int32 int32
bool ApproxEqual(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2, float delta=kDelta)
CompactLatticeWeightTpl< LatticeWeightTpl< float >, int32 > Weight
static void ReadFloatType(std::istream &strm, T &f)
Weight operator()(const Weight &w1, const Weight &w2) const
std::istream & Read(std::istream &strm)
LatticeWeightTpl ReverseWeight
std::ostream & Write(std::ostream &strm) const
LatticeWeightTpl< FloatType > Times(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
CompactLatticeWeightTpl< LatticeWeightTpl< FloatType >, IntType > Weight
CompactLatticeWeightTpl< BaseWeightType, IntType > Weight
void ConvertLatticeWeight(const LatticeWeightTpl< Float1 > &w_in, LatticeWeightTpl< Float2 > *w_out)
Define some ConvertLatticeWeight functions that are used in various lattice conversions...
static const CompactLatticeWeightTpl< WeightType, IntType > One()
std::istream & operator>>(std::istream &strm, LatticeWeightTpl< FloatType > &w)
std::ostream & Write(std::ostream &strm) const
double ConvertToCost(const LatticeWeightTpl< Float > &w)
static const LatticeWeightTpl Zero()
#define KALDI_ERR
Definition: kaldi-error.h:147
#define KALDI_WARN
Definition: kaldi-error.h:150
std::vector< IntType > string_
fst::StdArc::Weight Weight
int Compare(const LatticeWeightTpl< FloatType > &w1, const LatticeWeightTpl< FloatType > &w2)
Compare returns -1 if w1 < w2, +1 if w1 > w2, and 0 if w1 == w2.
static const CompactLatticeWeightTpl< WeightType, IntType > Zero()
static constexpr uint64 Properties()
bool operator==(const LatticeWeightTpl< FloatType > &wa, const LatticeWeightTpl< FloatType > &wb)
CompactLatticeWeightTpl Quantize(float delta=kDelta) const
static const std::string & Type()
std::istream & ReadNoParen(std::istream &strm, char separator)
static const CompactLatticeWeightTpl< WeightType, IntType > NoWeight()
CompactLatticeWeightTpl & operator=(const CompactLatticeWeightTpl< WeightType, IntType > &w)
bool operator()(const Weight &w1, const Weight &w2) const
const std::vector< IntType > & String() const
void SetString(const std::vector< IntType > &s)
friend std::istream & operator>>(std::istream &, LatticeWeightTpl< FloatType > &)