// pair-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: shumash@google.com (Masha Maria Shugrina) // // \file // Pair weight templated base class for weight classes that // contain two weights (e.g. Product, Lexicographic) #ifndef FST_LIB_PAIR_WEIGHT_H_ #define FST_LIB_PAIR_WEIGHT_H_ #include <climits> #include <stack> #include <string> #include <fst/weight.h> DECLARE_string(fst_weight_parentheses); DECLARE_string(fst_weight_separator); namespace fst { template<class W1, class W2> class PairWeight; template <class W1, class W2> istream &operator>>(istream &strm, PairWeight<W1, W2> &w); template<class W1, class W2> class PairWeight { public: friend istream &operator>><W1, W2>(istream&, PairWeight<W1, W2>&); typedef PairWeight<typename W1::ReverseWeight, typename W2::ReverseWeight> ReverseWeight; PairWeight() {} PairWeight(const PairWeight& w) : value1_(w.value1_), value2_(w.value2_) {} PairWeight(W1 w1, W2 w2) : value1_(w1), value2_(w2) {} static const PairWeight<W1, W2> &Zero() { static const PairWeight<W1, W2> zero(W1::Zero(), W2::Zero()); return zero; } static const PairWeight<W1, W2> &One() { static const PairWeight<W1, W2> one(W1::One(), W2::One()); return one; } static const PairWeight<W1, W2> &NoWeight() { static const PairWeight<W1, W2> no_weight(W1::NoWeight(), W2::NoWeight()); return no_weight; } istream &Read(istream &strm) { value1_.Read(strm); return value2_.Read(strm); } ostream &Write(ostream &strm) const { value1_.Write(strm); return value2_.Write(strm); } PairWeight<W1, W2> &operator=(const PairWeight<W1, W2> &w) { value1_ = w.Value1(); value2_ = w.Value2(); return *this; } bool Member() const { return value1_.Member() && value2_.Member(); } size_t Hash() const { size_t h1 = value1_.Hash(); size_t h2 = value2_.Hash(); const int lshift = 5; const int rshift = CHAR_BIT * sizeof(size_t) - 5; return h1 << lshift ^ h1 >> rshift ^ h2; } PairWeight<W1, W2> Quantize(float delta = kDelta) const { return PairWeight<W1, W2>(value1_.Quantize(delta), value2_.Quantize(delta)); } ReverseWeight Reverse() const { return ReverseWeight(value1_.Reverse(), value2_.Reverse()); } const W1& Value1() const { return value1_; } const W2& Value2() const { return value2_; } protected: void SetValue1(const W1 &w) { value1_ = w; } void SetValue2(const W2 &w) { value2_ = w; } // Reads PairWeight when there are not parentheses around pair terms inline static istream &ReadNoParen( istream &strm, PairWeight<W1, W2>& w, char separator) { int c; do { c = strm.get(); } while (isspace(c)); string s1; while (c != separator) { if (c == EOF) { strm.clear(std::ios::badbit); return strm; } s1 += c; c = strm.get(); } istringstream strm1(s1); W1 w1 = W1::Zero(); strm1 >> w1; // read second element W2 w2 = W2::Zero(); strm >> w2; w = PairWeight<W1, W2>(w1, w2); return strm; } // Reads PairWeight when there are parentheses around pair terms inline static istream &ReadWithParen( istream &strm, PairWeight<W1, W2>& w, char separator, char open_paren, char close_paren) { int c; do { c = strm.get(); } while (isspace(c)); if (c != open_paren) { FSTERROR() << " is fst_weight_parentheses flag set correcty? "; strm.clear(std::ios::failbit); return strm; } c = strm.get(); // read first element stack<int> parens; string s1; while (c != separator || !parens.empty()) { if (c == EOF) { strm.clear(std::ios::badbit); return strm; } s1 += c; // if parens encountered before separator, they must be matched if (c == open_paren) { parens.push(1); } else if (c == close_paren) { // Fail for mismatched parens if (parens.empty()) { strm.clear(std::ios::failbit); return strm; } parens.pop(); } c = strm.get(); } istringstream strm1(s1); W1 w1 = W1::Zero(); strm1 >> w1; // read second element string s2; c = strm.get(); while (c != EOF) { s2 += c; c = strm.get(); } if (s2.empty() || (s2[s2.size() - 1] != close_paren)) { FSTERROR() << " is fst_weight_parentheses flag set correcty? "; strm.clear(std::ios::failbit); return strm; } s2.erase(s2.size() - 1, 1); istringstream strm2(s2); W2 w2 = W2::Zero(); strm2 >> w2; w = PairWeight<W1, W2>(w1, w2); return strm; } private: W1 value1_; W2 value2_; }; template <class W1, class W2> inline bool operator==(const PairWeight<W1, W2> &w, const PairWeight<W1, W2> &v) { return w.Value1() == v.Value1() && w.Value2() == v.Value2(); } template <class W1, class W2> inline bool operator!=(const PairWeight<W1, W2> &w1, const PairWeight<W1, W2> &w2) { return w1.Value1() != w2.Value1() || w1.Value2() != w2.Value2(); } template <class W1, class W2> inline bool ApproxEqual(const PairWeight<W1, W2> &w1, const PairWeight<W1, W2> &w2, float delta = kDelta) { return ApproxEqual(w1.Value1(), w2.Value1(), delta) && ApproxEqual(w1.Value2(), w2.Value2(), delta); } template <class W1, class W2> inline ostream &operator<<(ostream &strm, const PairWeight<W1, W2> &w) { if(FLAGS_fst_weight_separator.size() != 1) { FSTERROR() << "FLAGS_fst_weight_separator.size() is not equal to 1"; strm.clear(std::ios::badbit); return strm; } char separator = FLAGS_fst_weight_separator[0]; if (FLAGS_fst_weight_parentheses.empty()) return strm << w.Value1() << separator << w.Value2(); if (FLAGS_fst_weight_parentheses.size() != 2) { FSTERROR() << "FLAGS_fst_weight_parentheses.size() is not equal to 2"; strm.clear(std::ios::badbit); return strm; } char open_paren = FLAGS_fst_weight_parentheses[0]; char close_paren = FLAGS_fst_weight_parentheses[1]; return strm << open_paren << w.Value1() << separator << w.Value2() << close_paren ; } template <class W1, class W2> inline istream &operator>>(istream &strm, PairWeight<W1, W2> &w) { if(FLAGS_fst_weight_separator.size() != 1) { FSTERROR() << "FLAGS_fst_weight_separator.size() is not equal to 1"; strm.clear(std::ios::badbit); return strm; } char separator = FLAGS_fst_weight_separator[0]; bool read_parens = !FLAGS_fst_weight_parentheses.empty(); if (read_parens) { if (FLAGS_fst_weight_parentheses.size() != 2) { FSTERROR() << "FLAGS_fst_weight_parentheses.size() is not equal to 2"; strm.clear(std::ios::badbit); return strm; } return PairWeight<W1, W2>::ReadWithParen( strm, w, separator, FLAGS_fst_weight_parentheses[0], FLAGS_fst_weight_parentheses[1]); } else { return PairWeight<W1, W2>::ReadNoParen(strm, w, separator); } } } // namespace fst #endif // FST_LIB_PAIR_WEIGHT_H_