Home | History | Annotate | Download | only in fst
      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 (at) 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 
     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 
    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