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 
32 DECLARE_string(fst_weight_parentheses);
33 DECLARE_string(fst_weight_separator);
34 
35 namespace fst {
36 
37 template<class W1, class W2> class PairWeight;
38 template <class W1, class W2>
39 istream &operator>>(istream &strm, PairWeight<W1, W2> &w);
40 
41 template<class W1, class W2>
42 class 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 
PairWeight()50   PairWeight() {}
51 
PairWeight(const PairWeight & w)52   PairWeight(const PairWeight& w) : value1_(w.value1_), value2_(w.value2_) {}
53 
PairWeight(W1 w1,W2 w2)54   PairWeight(W1 w1, W2 w2) : value1_(w1), value2_(w2) {}
55 
Zero()56   static const PairWeight<W1, W2> &Zero() {
57     static const PairWeight<W1, W2> zero(W1::Zero(), W2::Zero());
58     return zero;
59   }
60 
One()61   static const PairWeight<W1, W2> &One() {
62     static const PairWeight<W1, W2> one(W1::One(), W2::One());
63     return one;
64   }
65 
NoWeight()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 
Read(istream & strm)71   istream &Read(istream &strm) {
72     value1_.Read(strm);
73     return value2_.Read(strm);
74   }
75 
Write(ostream & strm)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 
Member()87   bool Member() const { return value1_.Member() && value2_.Member(); }
88 
Hash()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 
Reverse()102   ReverseWeight Reverse() const {
103     return ReverseWeight(value1_.Reverse(), value2_.Reverse());
104   }
105 
Value1()106   const W1& Value1() const { return value1_; }
107 
Value2()108   const W2& Value2() const { return value2_; }
109 
110  protected:
SetValue1(const W1 & w)111   void SetValue1(const W1 &w) { value1_ = w; }
SetValue2(const W2 & w)112   void SetValue2(const W2 &w) { value2_ = w; }
113 
114   // Reads PairWeight when there are not parentheses around pair terms
ReadNoParen(istream & strm,PairWeight<W1,W2> & w,char separator)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
ReadWithParen(istream & strm,PairWeight<W1,W2> & w,char separator,char open_paren,char close_paren)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 
212 template <class W1, class W2>
213 inline 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 
218 template <class W1, class W2>
219 inline 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 
225 template <class W1, class W2>
226 inline 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 
233 template <class W1, class W2>
234 inline 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 
255 template <class W1, class W2>
256 inline 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