1// pair-weight.h 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// Copyright 2005-2010 Google, Inc. 16// Author: shumash@google.com (Masha Maria Shugrina) 17// 18// \file 19// Pair weight templated base class for weight classes that 20// contain two weights (e.g. Product, Lexicographic) 21 22#ifndef FST_LIB_PAIR_WEIGHT_H_ 23#define FST_LIB_PAIR_WEIGHT_H_ 24 25#include <climits> 26#include <stack> 27#include <string> 28 29#include <fst/weight.h> 30 31 32DECLARE_string(fst_weight_parentheses); 33DECLARE_string(fst_weight_separator); 34 35namespace fst { 36 37template<class W1, class W2> class PairWeight; 38template <class W1, class W2> 39istream &operator>>(istream &strm, PairWeight<W1, W2> &w); 40 41template<class W1, class W2> 42class PairWeight { 43 public: 44 friend istream &operator>><W1, W2>(istream&, PairWeight<W1, W2>&); 45 46 typedef PairWeight<typename W1::ReverseWeight, 47 typename W2::ReverseWeight> 48 ReverseWeight; 49 50 PairWeight() {} 51 52 PairWeight(const PairWeight& w) : value1_(w.value1_), value2_(w.value2_) {} 53 54 PairWeight(W1 w1, W2 w2) : value1_(w1), value2_(w2) {} 55 56 static const PairWeight<W1, W2> &Zero() { 57 static const PairWeight<W1, W2> zero(W1::Zero(), W2::Zero()); 58 return zero; 59 } 60 61 static const PairWeight<W1, W2> &One() { 62 static const PairWeight<W1, W2> one(W1::One(), W2::One()); 63 return one; 64 } 65 66 static const PairWeight<W1, W2> &NoWeight() { 67 static const PairWeight<W1, W2> no_weight(W1::NoWeight(), W2::NoWeight()); 68 return no_weight; 69 } 70 71 istream &Read(istream &strm) { 72 value1_.Read(strm); 73 return value2_.Read(strm); 74 } 75 76 ostream &Write(ostream &strm) const { 77 value1_.Write(strm); 78 return value2_.Write(strm); 79 } 80 81 PairWeight<W1, W2> &operator=(const PairWeight<W1, W2> &w) { 82 value1_ = w.Value1(); 83 value2_ = w.Value2(); 84 return *this; 85 } 86 87 bool Member() const { return value1_.Member() && value2_.Member(); } 88 89 size_t Hash() const { 90 size_t h1 = value1_.Hash(); 91 size_t h2 = value2_.Hash(); 92 const int lshift = 5; 93 const int rshift = CHAR_BIT * sizeof(size_t) - 5; 94 return h1 << lshift ^ h1 >> rshift ^ h2; 95 } 96 97 PairWeight<W1, W2> Quantize(float delta = kDelta) const { 98 return PairWeight<W1, W2>(value1_.Quantize(delta), 99 value2_.Quantize(delta)); 100 } 101 102 ReverseWeight Reverse() const { 103 return ReverseWeight(value1_.Reverse(), value2_.Reverse()); 104 } 105 106 const W1& Value1() const { return value1_; } 107 108 const W2& Value2() const { return value2_; } 109 110 protected: 111 void SetValue1(const W1 &w) { value1_ = w; } 112 void SetValue2(const W2 &w) { value2_ = w; } 113 114 // Reads PairWeight when there are not parentheses around pair terms 115 inline static istream &ReadNoParen( 116 istream &strm, PairWeight<W1, W2>& w, char separator) { 117 int c; 118 do { 119 c = strm.get(); 120 } while (isspace(c)); 121 122 string s1; 123 while (c != separator) { 124 if (c == EOF) { 125 strm.clear(std::ios::badbit); 126 return strm; 127 } 128 s1 += c; 129 c = strm.get(); 130 } 131 istringstream strm1(s1); 132 W1 w1 = W1::Zero(); 133 strm1 >> w1; 134 135 // read second element 136 W2 w2 = W2::Zero(); 137 strm >> w2; 138 139 w = PairWeight<W1, W2>(w1, w2); 140 return strm; 141 } 142 143 // Reads PairWeight when there are parentheses around pair terms 144 inline static istream &ReadWithParen( 145 istream &strm, PairWeight<W1, W2>& w, 146 char separator, char open_paren, char close_paren) { 147 int c; 148 do { 149 c = strm.get(); 150 } while (isspace(c)); 151 if (c != open_paren) { 152 FSTERROR() << " is fst_weight_parentheses flag set correcty? "; 153 strm.clear(std::ios::failbit); 154 return strm; 155 } 156 c = strm.get(); 157 158 // read first element 159 stack<int> parens; 160 string s1; 161 while (c != separator || !parens.empty()) { 162 if (c == EOF) { 163 strm.clear(std::ios::badbit); 164 return strm; 165 } 166 s1 += c; 167 // if parens encountered before separator, they must be matched 168 if (c == open_paren) { 169 parens.push(1); 170 } else if (c == close_paren) { 171 // Fail for mismatched parens 172 if (parens.empty()) { 173 strm.clear(std::ios::failbit); 174 return strm; 175 } 176 parens.pop(); 177 } 178 c = strm.get(); 179 } 180 istringstream strm1(s1); 181 W1 w1 = W1::Zero(); 182 strm1 >> w1; 183 184 // read second element 185 string s2; 186 c = strm.get(); 187 while (c != EOF) { 188 s2 += c; 189 c = strm.get(); 190 } 191 if (s2.empty() || (s2[s2.size() - 1] != close_paren)) { 192 FSTERROR() << " is fst_weight_parentheses flag set correcty? "; 193 strm.clear(std::ios::failbit); 194 return strm; 195 } 196 197 s2.erase(s2.size() - 1, 1); 198 istringstream strm2(s2); 199 W2 w2 = W2::Zero(); 200 strm2 >> w2; 201 202 w = PairWeight<W1, W2>(w1, w2); 203 return strm; 204 } 205 206 private: 207 W1 value1_; 208 W2 value2_; 209 210}; 211 212template <class W1, class W2> 213inline bool operator==(const PairWeight<W1, W2> &w, 214 const PairWeight<W1, W2> &v) { 215 return w.Value1() == v.Value1() && w.Value2() == v.Value2(); 216} 217 218template <class W1, class W2> 219inline bool operator!=(const PairWeight<W1, W2> &w1, 220 const PairWeight<W1, W2> &w2) { 221 return w1.Value1() != w2.Value1() || w1.Value2() != w2.Value2(); 222} 223 224 225template <class W1, class W2> 226inline bool ApproxEqual(const PairWeight<W1, W2> &w1, 227 const PairWeight<W1, W2> &w2, 228 float delta = kDelta) { 229 return ApproxEqual(w1.Value1(), w2.Value1(), delta) && 230 ApproxEqual(w1.Value2(), w2.Value2(), delta); 231} 232 233template <class W1, class W2> 234inline ostream &operator<<(ostream &strm, const PairWeight<W1, W2> &w) { 235 if(FLAGS_fst_weight_separator.size() != 1) { 236 FSTERROR() << "FLAGS_fst_weight_separator.size() is not equal to 1"; 237 strm.clear(std::ios::badbit); 238 return strm; 239 } 240 char separator = FLAGS_fst_weight_separator[0]; 241 if (FLAGS_fst_weight_parentheses.empty()) 242 return strm << w.Value1() << separator << w.Value2(); 243 244 if (FLAGS_fst_weight_parentheses.size() != 2) { 245 FSTERROR() << "FLAGS_fst_weight_parentheses.size() is not equal to 2"; 246 strm.clear(std::ios::badbit); 247 return strm; 248 } 249 char open_paren = FLAGS_fst_weight_parentheses[0]; 250 char close_paren = FLAGS_fst_weight_parentheses[1]; 251 return strm << open_paren << w.Value1() << separator 252 << w.Value2() << close_paren ; 253} 254 255template <class W1, class W2> 256inline istream &operator>>(istream &strm, PairWeight<W1, W2> &w) { 257 if(FLAGS_fst_weight_separator.size() != 1) { 258 FSTERROR() << "FLAGS_fst_weight_separator.size() is not equal to 1"; 259 strm.clear(std::ios::badbit); 260 return strm; 261 } 262 char separator = FLAGS_fst_weight_separator[0]; 263 bool read_parens = !FLAGS_fst_weight_parentheses.empty(); 264 if (read_parens) { 265 if (FLAGS_fst_weight_parentheses.size() != 2) { 266 FSTERROR() << "FLAGS_fst_weight_parentheses.size() is not equal to 2"; 267 strm.clear(std::ios::badbit); 268 return strm; 269 } 270 return PairWeight<W1, W2>::ReadWithParen( 271 strm, w, separator, FLAGS_fst_weight_parentheses[0], 272 FLAGS_fst_weight_parentheses[1]); 273 } else { 274 return PairWeight<W1, W2>::ReadNoParen(strm, w, separator); 275 } 276} 277 278} // namespace fst 279 280#endif // FST_LIB_PAIR_WEIGHT_H_ 281