From 96a32415ab43377cf1575bd3f4f2980f58028209 Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 14 Aug 2015 11:51:42 +0800 Subject: add implementation for kaldi io (by ymz) --- .../src/tools/openfst/include/fst/string-weight.h | 560 +++++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 kaldi_io/src/tools/openfst/include/fst/string-weight.h (limited to 'kaldi_io/src/tools/openfst/include/fst/string-weight.h') diff --git a/kaldi_io/src/tools/openfst/include/fst/string-weight.h b/kaldi_io/src/tools/openfst/include/fst/string-weight.h new file mode 100644 index 0000000..1beeb33 --- /dev/null +++ b/kaldi_io/src/tools/openfst/include/fst/string-weight.h @@ -0,0 +1,560 @@ +// string-weight.h + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2005-2010 Google, Inc. +// Author: riley@google.com (Michael Riley) +// +// \file +// String weight set and associated semiring operation definitions. + +#ifndef FST_LIB_STRING_WEIGHT_H__ +#define FST_LIB_STRING_WEIGHT_H__ + +#include +#include + +#include +#include + +namespace fst { + +const int kStringInfinity = -1; // Label for the infinite string +const int kStringBad = -2; // Label for a non-string +const char kStringSeparator = '_'; // Label separator in strings + +// Determines whether to use left or right string semiring. Includes +// restricted versions that signal an error if proper prefixes +// (suffixes) would otherwise be returned by Plus, useful with various +// algorithms that require functional transducer input with the +// string semirings. +enum StringType { STRING_LEFT = 0, STRING_RIGHT = 1 , + STRING_LEFT_RESTRICT = 2, STRING_RIGHT_RESTRICT }; + +#define REVERSE_STRING_TYPE(S) \ + ((S) == STRING_LEFT ? STRING_RIGHT : \ + ((S) == STRING_RIGHT ? STRING_LEFT : \ + ((S) == STRING_LEFT_RESTRICT ? STRING_RIGHT_RESTRICT : \ + STRING_LEFT_RESTRICT))) + +template +class StringWeight; + +template +class StringWeightIterator; + +template +class StringWeightReverseIterator; + +template +bool operator==(const StringWeight &, const StringWeight &); + + +// String semiring: (longest_common_prefix/suffix, ., Infinity, Epsilon) +template +class StringWeight { + public: + typedef L Label; + typedef StringWeight ReverseWeight; + + friend class StringWeightIterator; + friend class StringWeightReverseIterator; + friend bool operator==<>(const StringWeight &, + const StringWeight &); + + StringWeight() { Init(); } + + template + StringWeight(const Iter &begin, const Iter &end) { + Init(); + for (Iter iter = begin; iter != end; ++iter) + PushBack(*iter); + } + + explicit StringWeight(L l) { Init(); PushBack(l); } + + static const StringWeight &Zero() { + static const StringWeight zero(kStringInfinity); + return zero; + } + + static const StringWeight &One() { + static const StringWeight one; + return one; + } + + static const StringWeight &NoWeight() { + static const StringWeight no_weight(kStringBad); + return no_weight; + } + + static const string &Type() { + static const string type = + S == STRING_LEFT ? "string" : + (S == STRING_RIGHT ? "right_string" : + (S == STRING_LEFT_RESTRICT ? "restricted_string" : + "right_restricted_string")); + return type; + } + + bool Member() const; + + istream &Read(istream &strm); + + ostream &Write(ostream &strm) const; + + size_t Hash() const; + + StringWeight Quantize(float delta = kDelta) const { + return *this; + } + + ReverseWeight Reverse() const; + + static uint64 Properties() { + return (S == STRING_LEFT || S == STRING_LEFT_RESTRICT ? + kLeftSemiring : kRightSemiring) | kIdempotent; + } + + // NB: This needs to be uncommented only if default fails for this impl. + // StringWeight &operator=(const StringWeight &w); + + // These operations combined with the StringWeightIterator and + // StringWeightReverseIterator provide the access and mutation of + // the string internal elements. + + // Common initializer among constructors. + void Init() { first_ = 0; } + + // Clear existing StringWeight. + void Clear() { first_ = 0; rest_.clear(); } + + size_t Size() const { return first_ ? rest_.size() + 1 : 0; } + + void PushFront(L l) { + if (first_) + rest_.push_front(first_); + first_ = l; + } + + void PushBack(L l) { + if (!first_) + first_ = l; + else + rest_.push_back(l); + } + + private: + L first_; // first label in string (0 if empty) + list rest_; // remaining labels in string +}; + + +// Traverses string in forward direction. +template +class StringWeightIterator { + public: + explicit StringWeightIterator(const StringWeight& w) + : first_(w.first_), rest_(w.rest_), init_(true), + iter_(rest_.begin()) {} + + bool Done() const { + if (init_) return first_ == 0; + else return iter_ == rest_.end(); + } + + const L& Value() const { return init_ ? first_ : *iter_; } + + void Next() { + if (init_) init_ = false; + else ++iter_; + } + + void Reset() { + init_ = true; + iter_ = rest_.begin(); + } + + private: + const L &first_; + const list &rest_; + bool init_; // in the initialized state? + typename list::const_iterator iter_; + + DISALLOW_COPY_AND_ASSIGN(StringWeightIterator); +}; + + +// Traverses string in backward direction. +template +class StringWeightReverseIterator { + public: + explicit StringWeightReverseIterator(const StringWeight& w) + : first_(w.first_), rest_(w.rest_), fin_(first_ == 0), + iter_(rest_.rbegin()) {} + + bool Done() const { return fin_; } + + const L& Value() const { return iter_ == rest_.rend() ? first_ : *iter_; } + + void Next() { + if (iter_ == rest_.rend()) fin_ = true; + else ++iter_; + } + + void Reset() { + fin_ = false; + iter_ = rest_.rbegin(); + } + + private: + const L &first_; + const list &rest_; + bool fin_; // in the final state? + typename list::const_reverse_iterator iter_; + + DISALLOW_COPY_AND_ASSIGN(StringWeightReverseIterator); +}; + + +// StringWeight member functions follow that require +// StringWeightIterator or StringWeightReverseIterator. + +template +inline istream &StringWeight::Read(istream &strm) { + Clear(); + int32 size; + ReadType(strm, &size); + for (int i = 0; i < size; ++i) { + L label; + ReadType(strm, &label); + PushBack(label); + } + return strm; +} + +template +inline ostream &StringWeight::Write(ostream &strm) const { + int32 size = Size(); + WriteType(strm, size); + for (StringWeightIterator iter(*this); !iter.Done(); iter.Next()) { + L label = iter.Value(); + WriteType(strm, label); + } + return strm; +} + +template +inline bool StringWeight::Member() const { + if (Size() != 1) + return true; + StringWeightIterator iter(*this); + return iter.Value() != kStringBad; +} + +template +inline typename StringWeight::ReverseWeight +StringWeight::Reverse() const { + ReverseWeight rw; + for (StringWeightIterator iter(*this); !iter.Done(); iter.Next()) + rw.PushFront(iter.Value()); + return rw; +} + +template +inline size_t StringWeight::Hash() const { + size_t h = 0; + for (StringWeightIterator iter(*this); !iter.Done(); iter.Next()) + h ^= h<<1 ^ iter.Value(); + return h; +} + +// NB: This needs to be uncommented only if default fails for this the impl. +// +// template +// inline StringWeight +// &StringWeight::operator=(const StringWeight &w) { +// if (this != &w) { +// Clear(); +// for (StringWeightIterator iter(w); !iter.Done(); iter.Next()) +// PushBack(iter.Value()); +// } +// return *this; +// } + +template +inline bool operator==(const StringWeight &w1, + const StringWeight &w2) { + if (w1.Size() != w2.Size()) + return false; + + StringWeightIterator iter1(w1); + StringWeightIterator iter2(w2); + + for (; !iter1.Done() ; iter1.Next(), iter2.Next()) + if (iter1.Value() != iter2.Value()) + return false; + + return true; +} + +template +inline bool operator!=(const StringWeight &w1, + const StringWeight &w2) { + return !(w1 == w2); +} + +template +inline bool ApproxEqual(const StringWeight &w1, + const StringWeight &w2, + float delta = kDelta) { + return w1 == w2; +} + +template +inline ostream &operator<<(ostream &strm, const StringWeight &w) { + StringWeightIterator iter(w); + if (iter.Done()) + return strm << "Epsilon"; + else if (iter.Value() == kStringInfinity) + return strm << "Infinity"; + else if (iter.Value() == kStringBad) + return strm << "BadString"; + else + for (size_t i = 0; !iter.Done(); ++i, iter.Next()) { + if (i > 0) + strm << kStringSeparator; + strm << iter.Value(); + } + return strm; +} + +template +inline istream &operator>>(istream &strm, StringWeight &w) { + string s; + strm >> s; + if (s == "Infinity") { + w = StringWeight::Zero(); + } else if (s == "Epsilon") { + w = StringWeight::One(); + } else { + w.Clear(); + char *p = 0; + for (const char *cs = s.c_str(); !p || *p != '\0'; cs = p + 1) { + int l = strtoll(cs, &p, 10); + if (p == cs || (*p != 0 && *p != kStringSeparator)) { + strm.clear(std::ios::badbit); + break; + } + w.PushBack(l); + } + } + return strm; +} + + +// Default is for the restricted left and right semirings. String +// equality is required (for non-Zero() input. This restriction +// is used in e.g. Determinize to ensure functional input. +template inline StringWeight +Plus(const StringWeight &w1, + const StringWeight &w2) { + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + if (w1 == StringWeight::Zero()) + return w2; + if (w2 == StringWeight::Zero()) + return w1; + + if (w1 != w2) { + FSTERROR() << "StringWeight::Plus: unequal arguments " + << "(non-functional FST?)" + << " w1 = " << w1 + << " w2 = " << w2; + return StringWeight::NoWeight(); + } + + return w1; +} + + +// Longest common prefix for left string semiring. +template inline StringWeight +Plus(const StringWeight &w1, + const StringWeight &w2) { + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + if (w1 == StringWeight::Zero()) + return w2; + if (w2 == StringWeight::Zero()) + return w1; + + StringWeight sum; + StringWeightIterator iter1(w1); + StringWeightIterator iter2(w2); + for (; !iter1.Done() && !iter2.Done() && iter1.Value() == iter2.Value(); + iter1.Next(), iter2.Next()) + sum.PushBack(iter1.Value()); + return sum; +} + + +// Longest common suffix for right string semiring. +template inline StringWeight +Plus(const StringWeight &w1, + const StringWeight &w2) { + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + if (w1 == StringWeight::Zero()) + return w2; + if (w2 == StringWeight::Zero()) + return w1; + + StringWeight sum; + StringWeightReverseIterator iter1(w1); + StringWeightReverseIterator iter2(w2); + for (; !iter1.Done() && !iter2.Done() && iter1.Value() == iter2.Value(); + iter1.Next(), iter2.Next()) + sum.PushFront(iter1.Value()); + return sum; +} + + +template +inline StringWeight Times(const StringWeight &w1, + const StringWeight &w2) { + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + if (w1 == StringWeight::Zero() || w2 == StringWeight::Zero()) + return StringWeight::Zero(); + + StringWeight prod(w1); + for (StringWeightIterator iter(w2); !iter.Done(); iter.Next()) + prod.PushBack(iter.Value()); + + return prod; +} + + +// Default is for left division in the left string and the +// left restricted string semirings. +template inline StringWeight +Divide(const StringWeight &w1, + const StringWeight &w2, + DivideType typ) { + + if (typ != DIVIDE_LEFT) { + FSTERROR() << "StringWeight::Divide: only left division is defined " + << "for the " << StringWeight::Type() << " semiring"; + return StringWeight::NoWeight(); + } + + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + + if (w2 == StringWeight::Zero()) + return StringWeight(kStringBad); + else if (w1 == StringWeight::Zero()) + return StringWeight::Zero(); + + StringWeight div; + StringWeightIterator iter(w1); + for (int i = 0; !iter.Done(); iter.Next(), ++i) { + if (i >= w2.Size()) + div.PushBack(iter.Value()); + } + return div; +} + + +// Right division in the right string semiring. +template inline StringWeight +Divide(const StringWeight &w1, + const StringWeight &w2, + DivideType typ) { + + if (typ != DIVIDE_RIGHT) { + FSTERROR() << "StringWeight::Divide: only right division is defined " + << "for the right string semiring"; + return StringWeight::NoWeight(); + } + + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + + if (w2 == StringWeight::Zero()) + return StringWeight(kStringBad); + else if (w1 == StringWeight::Zero()) + return StringWeight::Zero(); + + StringWeight div; + StringWeightReverseIterator iter(w1); + for (int i = 0; !iter.Done(); iter.Next(), ++i) { + if (i >= w2.Size()) + div.PushFront(iter.Value()); + } + return div; +} + + +// Right division in the right restricted string semiring. +template inline StringWeight +Divide(const StringWeight &w1, + const StringWeight &w2, + DivideType typ) { + + if (typ != DIVIDE_RIGHT) { + FSTERROR() << "StringWeight::Divide: only right division is defined " + << "for the right restricted string semiring"; + return StringWeight::NoWeight(); + } + + if (!w1.Member() || !w2.Member()) + return StringWeight::NoWeight(); + + if (w2 == StringWeight::Zero()) + return StringWeight(kStringBad); + else if (w1 == StringWeight::Zero()) + return StringWeight::Zero(); + + StringWeight div; + StringWeightReverseIterator iter(w1); + for (int i = 0; !iter.Done(); iter.Next(), ++i) { + if (i >= w2.Size()) + div.PushFront(iter.Value()); + } + return div; +} + + +// Product of string weight and an arbitray weight. +template +struct GallicWeight : public ProductWeight, W> { + typedef GallicWeight + ReverseWeight; + + GallicWeight() {} + + GallicWeight(StringWeight w1, W w2) + : ProductWeight, W>(w1, w2) {} + + explicit GallicWeight(const string &s, int *nread = 0) + : ProductWeight, W>(s, nread) {} + + GallicWeight(const ProductWeight, W> &w) + : ProductWeight, W>(w) {} +}; + +} // namespace fst + +#endif // FST_LIB_STRING_WEIGHT_H__ -- cgit v1.2.3-70-g09d2