diff options
Diffstat (limited to 'decoder')
| -rw-r--r-- | decoder/Makefile.am | 3 | ||||
| -rw-r--r-- | decoder/cdec_ff.cc | 3 | ||||
| -rw-r--r-- | decoder/ff_const_reorder.cc | 1118 | ||||
| -rw-r--r-- | decoder/ff_const_reorder.h | 43 | ||||
| -rw-r--r-- | decoder/ff_const_reorder_common.h | 1348 | 
5 files changed, 2514 insertions, 1 deletions
| diff --git a/decoder/Makefile.am b/decoder/Makefile.am index 78ab4d63..f9f90cfb 100644 --- a/decoder/Makefile.am +++ b/decoder/Makefile.am @@ -46,6 +46,8 @@ libcdec_a_SOURCES = \    ff_bleu.h \    ff_charset.h \    ff_conll.h \ +  ff_const_reorder_common.h \ +  ff_const_reorder.h \    ff_context.h \    ff_csplit.h \    ff_external.h \ @@ -113,6 +115,7 @@ libcdec_a_SOURCES = \    ff_charset.cc \    ff_conll.cc \    ff_context.cc \ +  ff_const_reorder.cc \    ff_csplit.cc \    ff_external.cc \    ff_factory.cc \ diff --git a/decoder/cdec_ff.cc b/decoder/cdec_ff.cc index 7f7e075b..6f7227aa 100644 --- a/decoder/cdec_ff.cc +++ b/decoder/cdec_ff.cc @@ -3,6 +3,7 @@  #include "ff.h"  #include "ff_basic.h"  #include "ff_context.h" +#include "ff_const_reorder.h"  #include "ff_spans.h"  #include "ff_lm.h"  #include "ff_klm.h" @@ -77,6 +78,6 @@ void register_feature_functions() {    ff_registry.Register("WordPairFeatures", new FFFactory<WordPairFeatures>);    ff_registry.Register("SourcePathFeatures", new FFFactory<SourcePathFeatures>);    ff_registry.Register("WordSet", new FFFactory<WordSet>); +  ff_registry.Register("ConstReorderFeature", new FFFactory<ConstReorderFeature>);    ff_registry.Register("External", new FFFactory<ExternalFeature>);  } - diff --git a/decoder/ff_const_reorder.cc b/decoder/ff_const_reorder.cc new file mode 100644 index 00000000..f1a6f7cb --- /dev/null +++ b/decoder/ff_const_reorder.cc @@ -0,0 +1,1118 @@ +#include "ff_const_reorder.h" + +#include "filelib.h" +#include "stringlib.h" +#include "hg.h" +#include "sentence_metadata.h" +#include "hash.h" +#include "ff_const_reorder_common.h" + +#include <sstream> +#include <string> +#include <vector> +#include <stdio.h> + +using namespace std; +using namespace const_reorder; + +typedef HASH_MAP<std::string, vector<double> > MapClassifier; + +inline bool is_inside(int i, int left, int right) { +  if (i < left || i > right) return false; +  return true; +} + +/* + * assume i <= j + * [i, j] is inside [left, right] or [i, j] equates to [left, right] + */ +inline bool is_inside(int i, int j, int left, int right) { +  if (i >= left && j <= right) return true; +  return false; +} + +/* + * assume i <= j + * [i, j] is inside [left, right], but [i, j] not equal to [left, right] + */ +inline bool is_proper_inside(int i, int j, int left, int right) { +  if (i >= left && j <= right && right - left > j - i) return true; +  return false; +} + +/* + * assume i <= j + * [i, j] is proper proper inside [left, right] + */ +inline bool is_proper_proper_inside(int i, int j, int left, int right) { +  if (i > left && j < right) return true; +  return false; +} + +inline bool is_overlap(int left1, int right1, int left2, int right2) { +  if (is_inside(left1, left2, right2) || is_inside(left2, left1, right1)) +    return true; + +  return false; +} + +inline void NewAndCopyCharArray(char** p, const char* q) { +  if (q != NULL) { +    (*p) = new char[strlen(q) + 1]; +    strcpy((*p), q); +  } else +    (*p) = NULL; +} + +// TODO:to make the alignment more efficient +struct TargetTranslation { +  TargetTranslation(int begin_pos, int end_pos,int e_num_word) +      : begin_pos_(begin_pos), +        end_pos_(end_pos), +        e_num_words_(e_num_word), +        vec_left_most_(end_pos - begin_pos + 1, e_num_word), +        vec_right_most_(end_pos - begin_pos + 1, -1), +        vec_f_align_bit_array_(end_pos - begin_pos + 1), +        vec_e_align_bit_array_(e_num_word) { +    int len = end_pos - begin_pos + 1; +    align_.reserve(1.5 * len); +  } + +  void InsertAlignmentPoint(int s, int t) { +    int i = s - begin_pos_; + +    vector<bool>& b = vec_f_align_bit_array_[i]; +    if (b.empty()) b.resize(e_num_words_); +    b[t] = 1; + +    vector<bool>& a = vec_e_align_bit_array_[t]; +    if (a.empty()) a.resize(end_pos_ - begin_pos_ + 1); +    a[i] = 1; + +    align_.push_back({s, t}); + +    if (t > vec_right_most_[i]) vec_right_most_[i] = t; +    if (t < vec_left_most_[i]) vec_left_most_[i] = t; +  } + +  /* +   * given a source span [begin, end], whether its target side is continuous, +   * return "0": the source span is translated silently +   * return "1": there is at least on word inside its target span, this word +   * doesn't align to any word inside [begin, end], but outside [begin, end] +   * return "2": otherwise +   */ +  string IsTargetConstinousSpan(int begin, int end) const { +    int target_begin, target_end; +    FindLeftRightMostTargetSpan(begin, end, target_begin, target_end); +    if (target_begin == -1) return "0"; + +    for (int i = target_begin; i <= target_end; i++) { +      if (vec_e_align_bit_array_[i].empty()) continue; +      int j = begin; +      for (; j <= end; j++) { +        if (vec_e_align_bit_array_[i][j - begin_pos_]) break; +      } +      if (j == end + 1)  // e[i] is aligned, but e[i] doesn't align to any +                         // source word in [begin_pos, end_pos] +        return "1"; +    } +    return "2"; +  } + +  string IsTargetConstinousSpan2(int begin, int end) const { +    int target_begin, target_end; +    FindLeftRightMostTargetSpan(begin, end, target_begin, target_end); +    if (target_begin == -1) return "Unaligned"; + +    for (int i = target_begin; i <= target_end; i++) { +      if (vec_e_align_bit_array_[i].empty()) continue; +      int j = begin; +      for (; j <= end; j++) { +        if (vec_e_align_bit_array_[i][j - begin_pos_]) break; +      } +      if (j == end + 1)  // e[i] is aligned, but e[i] doesn't align to any +                         // source word in [begin_pos, end_pos] +        return "Discon't"; +    } +    return "Con't"; +  } + +  void FindLeftRightMostTargetSpan(int begin, int end, int& target_begin, +                                   int& target_end) const { +    int b = begin - begin_pos_; +    int e = end - begin_pos_ + 1; + +    target_begin = vec_left_most_[b]; +    target_end = vec_right_most_[b]; +    for (int i = b + 1; i < e; i++) { +      if (target_begin > vec_left_most_[i]) target_begin = vec_left_most_[i]; +      if (target_end < vec_right_most_[i]) target_end = vec_right_most_[i]; +    } +    if (target_end == -1) target_begin = -1; +    return; + +    target_begin = e_num_words_; +    target_end = -1; + +    for (int i = begin - begin_pos_; i < end - begin_pos_ + 1; i++) { +      if (vec_f_align_bit_array_[i].empty()) continue; +      for (int j = 0; j < target_begin; j++) +        if (vec_f_align_bit_array_[i][j]) { +          target_begin = j; +          break; +        } +    } +    for (int i = end - begin_pos_; i > begin - begin_pos_ - 1; i--) { +      if (vec_f_align_bit_array_[i].empty()) continue; +      for (int j = e_num_words_ - 1; j > target_end; j--) +        if (vec_f_align_bit_array_[i][j]) { +          target_end = j; +          break; +        } +    } + +    if (target_end == -1) target_begin = -1; +  } + +  const uint16_t begin_pos_, end_pos_;              // the position in input +  const uint16_t e_num_words_; +  vector<AlignmentPoint> align_; + + private: +  vector<short> vec_left_most_; +  vector<short> vec_right_most_; +  vector<vector<bool> > vec_f_align_bit_array_; +  vector<vector<bool> > vec_e_align_bit_array_; +}; + +struct FocusedConstituent { +  FocusedConstituent(const SParsedTree* pTree) { +    if (pTree == NULL) return; +    for (size_t i = 0; i < pTree->m_vecTerminals.size(); i++) { +      STreeItem* pParent = pTree->m_vecTerminals[i]->m_ptParent; + +      while (pParent != NULL) { +        // if (pParent->m_vecChildren.size() > 1 && pParent->m_iEnd - +        // pParent->m_iBegin > 5) { +        // if (pParent->m_vecChildren.size() > 1) { +        if (true) { + +          // do constituent reordering for all children of pParent +          if (strcmp(pParent->m_pszTerm, "ROOT")) +            focus_parents_.push_back(pParent); +        } +        if (pParent->m_iBrotherIndex != 0) break; +        pParent = pParent->m_ptParent; +      } +    } +  } + +  ~FocusedConstituent() {  // TODO +    focus_parents_.clear(); +  } + +  vector<STreeItem*> focus_parents_; +}; + +typedef SPredicateItem FocusedPredicate; + +struct FocusedSRL { +  FocusedSRL(const SSrlSentence* srl) { +    if (srl == NULL) return; +    for (size_t i = 0; i < srl->m_vecPred.size(); i++) { +      if (strcmp(srl->m_pTree->m_vecTerminals[srl->m_vecPred[i]->m_iPosition] +                     ->m_ptParent->m_pszTerm, +                 "VA") == 0) +        continue; +      focus_predicates_.push_back( +          new FocusedPredicate(srl->m_pTree, srl->m_vecPred[i])); +    } +  } + +  ~FocusedSRL() { focus_predicates_.clear(); } + +  vector<const FocusedPredicate*> focus_predicates_; +}; + +struct ConstReorderFeatureImpl { +  ConstReorderFeatureImpl(const std::string& param) { + +    b_block_feature_ = false; +    b_order_feature_ = false; +    b_srl_block_feature_ = false; +    b_srl_order_feature_ = false; + +    vector<string> terms; +    SplitOnWhitespace(param, &terms); +    if (terms.size() == 1) { +      b_block_feature_ = true; +      b_order_feature_ = true; +    } else if (terms.size() >= 3) { +      if (terms[1].compare("1") == 0) b_block_feature_ = true; +      if (terms[2].compare("1") == 0) b_order_feature_ = true; +      if (terms.size() == 6) { +        if (terms[4].compare("1") == 0) b_srl_block_feature_ = true; +        if (terms[5].compare("1") == 0) b_srl_order_feature_ = true; + +        assert(b_srl_block_feature_ || b_srl_order_feature_); +      } + +    } else { +      assert("ERROR"); +    } + +    const_reorder_classifier_left_ = NULL; +    const_reorder_classifier_right_ = NULL; + +    srl_reorder_classifier_left_ = NULL; +    srl_reorder_classifier_right_ = NULL; + +    if (b_order_feature_) { +      InitializeClassifier((terms[0] + string(".left")).c_str(), +                           &const_reorder_classifier_left_); +      InitializeClassifier((terms[0] + string(".right")).c_str(), +                           &const_reorder_classifier_right_); +    } + +    if (b_srl_order_feature_) { +      InitializeClassifier((terms[3] + string(".left")).c_str(), +                           &srl_reorder_classifier_left_); +      InitializeClassifier((terms[3] + string(".right")).c_str(), +                           &srl_reorder_classifier_right_); +    } + +    parsed_tree_ = NULL; +    focused_consts_ = NULL; + +    srl_sentence_ = NULL; +    focused_srl_ = NULL; + +    map_left_ = NULL; +    map_right_ = NULL; + +    map_srl_left_ = NULL; +    map_srl_right_ = NULL; + +    dict_block_status_ = new Dict(); +    dict_block_status_->Convert("Unaligned", false); +    dict_block_status_->Convert("Discon't", false); +    dict_block_status_->Convert("Con't", false); +  } + +  ~ConstReorderFeatureImpl() { +    if (const_reorder_classifier_left_) delete const_reorder_classifier_left_; +    if (const_reorder_classifier_right_) delete const_reorder_classifier_right_; +    if (srl_reorder_classifier_left_) delete srl_reorder_classifier_left_; +    if (srl_reorder_classifier_right_) delete srl_reorder_classifier_right_; +    FreeSentenceVariables(); + +    delete dict_block_status_; +  } + +  static int ReserveStateSize() { return 1 * sizeof(TargetTranslation*); } + +  void InitializeInputSentence(const std::string& parse_file, +                               const std::string& srl_file) { +    FreeSentenceVariables(); +    if (b_srl_block_feature_ || b_srl_order_feature_) { +      assert(srl_file != ""); +      srl_sentence_ = ReadSRLSentence(srl_file); +      parsed_tree_ = srl_sentence_->m_pTree; +    } else { +      assert(parse_file != ""); +      srl_sentence_ = NULL; +      parsed_tree_ = ReadParseTree(parse_file); +    } + +    if (b_block_feature_ || b_order_feature_) { +      focused_consts_ = new FocusedConstituent(parsed_tree_); + +      if (b_order_feature_) { +        // we can do the classifier "off-line" +        map_left_ = new MapClassifier(); +        map_right_ = new MapClassifier(); +        InitializeConstReorderClassifierOutput(); +      } +    } + +    if (b_srl_block_feature_ || b_srl_order_feature_) { +      focused_srl_ = new FocusedSRL(srl_sentence_); + +      if (b_srl_order_feature_) { +        map_srl_left_ = new MapClassifier(); +        map_srl_right_ = new MapClassifier(); +        InitializeSRLReorderClassifierOutput(); +      } +    } + +    if (parsed_tree_ != NULL) { +      size_t i = parsed_tree_->m_vecTerminals.size(); +      vec_target_tran_.reserve(20 * i * i * i); +    } else +      vec_target_tran_.reserve(1000000); +  } + +  void SetConstReorderFeature(const Hypergraph::Edge& edge, +                              SparseVector<double>* features, +                              const vector<const void*>& ant_states, +                              void* state) { +    if (parsed_tree_ == NULL) return; + +    short int begin = edge.i_, end = edge.j_ - 1; + +    typedef TargetTranslation* PtrTargetTranslation; +    PtrTargetTranslation* remnant = +        reinterpret_cast<PtrTargetTranslation*>(state); + +    vector<const TargetTranslation*> vec_node; +    vec_node.reserve(edge.tail_nodes_.size()); +    for (size_t i = 0; i < edge.tail_nodes_.size(); i++) { +      const PtrTargetTranslation* astate = +          reinterpret_cast<const PtrTargetTranslation*>(ant_states[i]); +      vec_node.push_back(astate[0]); +    } + +    int e_num_word = edge.rule_->e_.size(); +    for (size_t i = 0; i < vec_node.size(); i++) { +      e_num_word += vec_node[i]->e_num_words_; +      e_num_word--; +    } + +    remnant[0] = new TargetTranslation(begin, end, e_num_word); +    vec_target_tran_.push_back(remnant[0]); + +    // reset the alignment +    // for the source side, we know its position in source sentence +    // for the target side, we always assume its starting position is 0 +    unsigned vc = 0; +    const TRulePtr rule = edge.rule_; +    std::vector<int> f_index(rule->f_.size()); +    int index = edge.i_; +    for (unsigned i = 0; i < rule->f_.size(); i++) { +      f_index[i] = index; +      const WordID& c = rule->f_[i]; +      if (c < 1) +        index = vec_node[vc++]->end_pos_ + 1; +      else +        index++; +    } +    assert(vc == vec_node.size()); +    assert(index == edge.j_); + +    std::vector<int> e_index(rule->e_.size()); +    index = 0; +    vc = 0; +    for (unsigned i = 0; i < rule->e_.size(); i++) { +      e_index[i] = index; +      const WordID& c = rule->e_[i]; +      if (c < 1) { +        index += vec_node[-c]->e_num_words_; +        vc++; +      } else +        index++; +    } +    assert(vc == vec_node.size()); + +    size_t nt_pos = 0; +    for (size_t i = 0; i < edge.rule_->f_.size(); i++) { +      if (edge.rule_->f_[i] > 0) continue; + +      // it's an NT +      size_t j; +      for (j = 0; j < edge.rule_->e_.size(); j++) +        if (edge.rule_->e_[j] * -1 == nt_pos) break; +      assert(j != edge.rule_->e_.size()); +      nt_pos++; + +      // i aligns j +      int eindex = e_index[j]; +      const vector<AlignmentPoint>& align = +          vec_node[-1 * edge.rule_->e_[j]]->align_; +      for (size_t k = 0; k < align.size(); k++) { +        remnant[0]->InsertAlignmentPoint(align[k].s_, eindex + align[k].t_); +      } +    } +    for (size_t i = 0; i < edge.rule_->a_.size(); i++) { +      int findex = f_index[edge.rule_->a_[i].s_]; +      int eindex = e_index[edge.rule_->a_[i].t_]; +      remnant[0]->InsertAlignmentPoint(findex, eindex); +    } + +    // till now, we finished setting state values +    // next, use the state values to calculate constituent reorder feature +    SetConstReorderFeature(begin, end, features, remnant[0], +                           vec_node, f_index); +  } + +  void SetConstReorderFeature(short int begin, short int end, +                              SparseVector<double>* features, +                              const TargetTranslation* target_translation, +                              const vector<const TargetTranslation*>& vec_node, +                              std::vector<int>& /*findex*/) { +    if (b_srl_block_feature_ || b_srl_order_feature_) { +      double logprob_srl_reorder_left = 0.0, logprob_srl_reorder_right = 0.0; +      for (size_t i = 0; i < focused_srl_->focus_predicates_.size(); i++) { +        const FocusedPredicate* pred = focused_srl_->focus_predicates_[i]; +        if (!is_overlap(begin, end, pred->begin_, pred->end_)) +          continue;  // have no overlap between this predicate (with its +                     // argument) and the current edge + +        size_t j; +        for (j = 0; j < vec_node.size(); j++) { +          if (is_inside(pred->begin_, pred->end_, vec_node[j]->begin_pos_, +                        vec_node[j]->end_pos_)) +            break; +        } +        if (j < vec_node.size()) continue; + +        vector<int> vecBlockStatus; +        vecBlockStatus.reserve(pred->vec_items_.size()); +        for (j = 0; j < pred->vec_items_.size(); j++) { +          const STreeItem* con1 = pred->vec_items_[j]->tree_item_; +          if (con1->m_iBegin < begin || con1->m_iEnd > end) { +            vecBlockStatus.push_back(0); +            continue; +          }  // the node is partially outside the current edge + +          string type = target_translation->IsTargetConstinousSpan2( +              con1->m_iBegin, con1->m_iEnd); +          vecBlockStatus.push_back(dict_block_status_->Convert(type, false)); + +          if (!b_srl_block_feature_) continue; +          // see if the node is covered by an NT +          size_t k; +          for (k = 0; k < vec_node.size(); k++) { +            if (is_inside(con1->m_iBegin, con1->m_iEnd, vec_node[k]->begin_pos_, +                          vec_node[k]->end_pos_)) +              break; +          } +          if (k < vec_node.size()) continue; +          int f_id = FD::Convert(string(pred->vec_items_[j]->role_) + type); +          if (f_id) features->add_value(f_id, 1); +        } + +        if (!b_srl_order_feature_) continue; + +        vector<int> vecPosition, vecRelativePosition; +        vector<int> vecRightPosition, vecRelativeRightPosition; +        vecPosition.reserve(pred->vec_items_.size()); +        vecRelativePosition.reserve(pred->vec_items_.size()); +        vecRightPosition.reserve(pred->vec_items_.size()); +        vecRelativeRightPosition.reserve(pred->vec_items_.size()); +        for (j = 0; j < pred->vec_items_.size(); j++) { +          const STreeItem* con1 = pred->vec_items_[j]->tree_item_; +          if (con1->m_iBegin < begin || con1->m_iEnd > end) { +            vecPosition.push_back(-1); +            vecRightPosition.push_back(-1); +            continue; +          }  // the node is partially outside the current edge +          int left1 = -1, right1 = -1; +          target_translation->FindLeftRightMostTargetSpan( +              con1->m_iBegin, con1->m_iEnd, left1, right1); +          vecPosition.push_back(left1); +          vecRightPosition.push_back(right1); +        } +        fnGetRelativePosition(vecPosition, vecRelativePosition); +        fnGetRelativePosition(vecRightPosition, vecRelativeRightPosition); + +        for (j = 1; j < pred->vec_items_.size(); j++) { +          const STreeItem* con1 = pred->vec_items_[j - 1]->tree_item_; +          const STreeItem* con2 = pred->vec_items_[j]->tree_item_; + +          if (con1->m_iBegin < begin || con2->m_iEnd > end) +            continue;  // one of the two nodes is partially outside the current +                       // edge + +          // both con1 and con2 are covered, need to check if they are covered +          // by the same NT +          size_t k; +          for (k = 0; k < vec_node.size(); k++) { +            if (is_inside(con1->m_iBegin, con2->m_iEnd, vec_node[k]->begin_pos_, +                          vec_node[k]->end_pos_)) +              break; +          } +          if (k < vec_node.size()) continue; + +          // they are not covered bye the same NT +          string outcome; +          string key; +          GenerateKey(pred->vec_items_[j - 1]->tree_item_, +                      pred->vec_items_[j]->tree_item_, vecBlockStatus[j - 1], +                      vecBlockStatus[j], key); + +          fnGetOutcome(vecRelativePosition[j - 1], vecRelativePosition[j], +                       outcome); +          double prob = CalculateConstReorderProb(srl_reorder_classifier_left_, +                                                  map_srl_left_, key, outcome); +          // printf("%s %s %f\n", ostr.str().c_str(), outcome.c_str(), prob); +          logprob_srl_reorder_left += log10(prob); + +          fnGetOutcome(vecRelativeRightPosition[j - 1], +                       vecRelativeRightPosition[j], outcome); +          prob = CalculateConstReorderProb(srl_reorder_classifier_right_, +                                           map_srl_right_, key, outcome); +          logprob_srl_reorder_right += log10(prob); +        } +      } + +      if (b_srl_order_feature_) { +        int f_id = FD::Convert("SRLReorderFeatureLeft"); +        if (f_id && logprob_srl_reorder_left != 0.0) +          features->set_value(f_id, logprob_srl_reorder_left); +        f_id = FD::Convert("SRLReorderFeatureRight"); +        if (f_id && logprob_srl_reorder_right != 0.0) +          features->set_value(f_id, logprob_srl_reorder_right); +      } +    } + +    if (b_block_feature_ || b_order_feature_) { +      double logprob_const_reorder_left = 0.0, +             logprob_const_reorder_right = 0.0; + +      for (size_t i = 0; i < focused_consts_->focus_parents_.size(); i++) { +        STreeItem* parent = focused_consts_->focus_parents_[i]; +        if (!is_overlap(begin, end, parent->m_iBegin, +                        parent->m_iEnd)) +          continue;  // have no overlap between this parent node and the current +                     // edge + +        size_t j; +        for (j = 0; j < vec_node.size(); j++) { +          if (is_inside(parent->m_iBegin, parent->m_iEnd, +                        vec_node[j]->begin_pos_, vec_node[j]->end_pos_)) +            break; +        } +        if (j < vec_node.size()) continue; + +        if (b_block_feature_) { +          if (parent->m_iBegin >= begin && +              parent->m_iEnd <= end) { +            string type = target_translation->IsTargetConstinousSpan2( +                parent->m_iBegin, parent->m_iEnd); +            int f_id = FD::Convert(string(parent->m_pszTerm) + type); +            if (f_id) features->add_value(f_id, 1); +          } +        } + +        if (parent->m_vecChildren.size() == 1 || !b_order_feature_) continue; + +        vector<int> vecChunkBlock; +        vecChunkBlock.reserve(parent->m_vecChildren.size()); + +        for (j = 0; j < parent->m_vecChildren.size(); j++) { +          STreeItem* con1 = parent->m_vecChildren[j]; +          if (con1->m_iBegin < begin || con1->m_iEnd > end) { +            vecChunkBlock.push_back(0); +            continue; +          }  // the node is partially outside the current edge + +          string type = target_translation->IsTargetConstinousSpan2( +              con1->m_iBegin, con1->m_iEnd); +          vecChunkBlock.push_back(dict_block_status_->Convert(type, false)); + +          /*if (!b_block_feature_) continue; +          //see if the node is covered by an NT +          size_t k; +          for (k = 0; k < vec_node.size(); k++) { +                  if (is_inside(con1->m_iBegin, con1->m_iEnd, +          vec_node[k]->begin_pos_, vec_node[k]->end_pos_)) +                          break; +          } +          if (k < vec_node.size()) continue; +          int f_id = FD::Convert(string(con1->m_pszTerm) + type); +          if (f_id) +                  features->add_value(f_id, 1);*/ +        } + +        if (!b_order_feature_) continue; + +        vector<int> vecPosition, vecRelativePosition; +        vector<int> vecRightPosition, vecRelativeRightPosition; +        vecPosition.reserve(parent->m_vecChildren.size()); +        vecRelativePosition.reserve(parent->m_vecChildren.size()); +        vecRightPosition.reserve(parent->m_vecChildren.size()); +        vecRelativeRightPosition.reserve(parent->m_vecChildren.size()); +        for (j = 0; j < parent->m_vecChildren.size(); j++) { +          STreeItem* con1 = parent->m_vecChildren[j]; +          if (con1->m_iBegin < begin || con1->m_iEnd > end) { +            vecPosition.push_back(-1); +            vecRightPosition.push_back(-1); +            continue; +          }  // the node is partially outside the current edge +          int left1 = -1, right1 = -1; +          target_translation->FindLeftRightMostTargetSpan( +              con1->m_iBegin, con1->m_iEnd, left1, right1); +          vecPosition.push_back(left1); +          vecRightPosition.push_back(right1); +        } +        fnGetRelativePosition(vecPosition, vecRelativePosition); +        fnGetRelativePosition(vecRightPosition, vecRelativeRightPosition); + +        for (j = 1; j < parent->m_vecChildren.size(); j++) { +          STreeItem* con1 = parent->m_vecChildren[j - 1]; +          STreeItem* con2 = parent->m_vecChildren[j]; + +          if (con1->m_iBegin < begin || con2->m_iEnd > end) +            continue;  // one of the two nodes is partially outside the current +                       // edge + +          // both con1 and con2 are covered, need to check if they are covered +          // by the same NT +          size_t k; +          for (k = 0; k < vec_node.size(); k++) { +            if (is_inside(con1->m_iBegin, con2->m_iEnd, vec_node[k]->begin_pos_, +                          vec_node[k]->end_pos_)) +              break; +          } +          if (k < vec_node.size()) continue; + +          // they are not covered bye the same NT +          string outcome; +          string key; +          GenerateKey(parent->m_vecChildren[j - 1], parent->m_vecChildren[j], +                      vecChunkBlock[j - 1], vecChunkBlock[j], key); + +          fnGetOutcome(vecRelativePosition[j - 1], vecRelativePosition[j], +                       outcome); +          double prob = CalculateConstReorderProb( +              const_reorder_classifier_left_, map_left_, key, outcome); +          // printf("%s %s %f\n", ostr.str().c_str(), outcome.c_str(), prob); +          logprob_const_reorder_left += log10(prob); + +          fnGetOutcome(vecRelativeRightPosition[j - 1], +                       vecRelativeRightPosition[j], outcome); +          prob = CalculateConstReorderProb(const_reorder_classifier_right_, +                                           map_right_, key, outcome); +          logprob_const_reorder_right += log10(prob); +        } +      } + +      if (b_order_feature_) { +        int f_id = FD::Convert("ConstReorderFeatureLeft"); +        if (f_id && logprob_const_reorder_left != 0.0) +          features->set_value(f_id, logprob_const_reorder_left); +        f_id = FD::Convert("ConstReorderFeatureRight"); +        if (f_id && logprob_const_reorder_right != 0.0) +          features->set_value(f_id, logprob_const_reorder_right); +      } +    } +  } + + private: +  void Byte_to_Char(unsigned char* str, int n) { +    str[0] = (n & 255); +    str[1] = n / 256; +  } +  void GenerateKey(const STreeItem* pCon1, const STreeItem* pCon2, +                   int iBlockStatus1, int iBlockStatus2, string& key) { +    assert(iBlockStatus1 != 0); +    assert(iBlockStatus2 != 0); +    unsigned char szTerm[1001]; +    Byte_to_Char(szTerm, pCon1->m_iBegin); +    Byte_to_Char(szTerm + 2, pCon2->m_iEnd); +    szTerm[4] = (char)iBlockStatus1; +    szTerm[5] = (char)iBlockStatus2; +    szTerm[6] = '\0'; +    // sprintf(szTerm, "%d|%d|%d|%d|%s|%s", pCon1->m_iBegin, pCon1->m_iEnd, +    // pCon2->m_iBegin, pCon2->m_iEnd, strBlockStatus1.c_str(), +    // strBlockStatus2.c_str()); +    key = string(szTerm, szTerm + 6); +  } +  void InitializeConstReorderClassifierOutput() { +    if (!b_order_feature_) return; +    int size_block_status = dict_block_status_->max(); + +    for (size_t i = 0; i < focused_consts_->focus_parents_.size(); i++) { +      STreeItem* parent = focused_consts_->focus_parents_[i]; + +      for (size_t j = 1; j < parent->m_vecChildren.size(); j++) { +        for (size_t k = 1; k <= size_block_status; k++) { +          for (size_t l = 1; l <= size_block_status; l++) { +            ostringstream ostr; +            GenerateFeature(parsed_tree_, parent, j, +                            dict_block_status_->Convert(k), +                            dict_block_status_->Convert(l), ostr); + +            string strKey; +            GenerateKey(parent->m_vecChildren[j - 1], parent->m_vecChildren[j], +                        k, l, strKey); + +            vector<double> vecOutput; +            const_reorder_classifier_left_->fnEval(ostr.str().c_str(), +                                                   vecOutput); +            (*map_left_)[strKey] = vecOutput; + +            const_reorder_classifier_right_->fnEval(ostr.str().c_str(), +                                                    vecOutput); +            (*map_right_)[strKey] = vecOutput; +          } +        } +      } +    } +  } + +  void InitializeSRLReorderClassifierOutput() { +    if (!b_srl_order_feature_) return; +    int size_block_status = dict_block_status_->max(); + +    for (size_t i = 0; i < focused_srl_->focus_predicates_.size(); i++) { +      const FocusedPredicate* pred = focused_srl_->focus_predicates_[i]; + +      for (size_t j = 1; j < pred->vec_items_.size(); j++) { +        for (size_t k = 1; k <= size_block_status; k++) { +          for (size_t l = 1; l <= size_block_status; l++) { +            ostringstream ostr; + +            SArgumentReorderModel::fnGenerateFeature( +                parsed_tree_, pred->pred_, pred, j, +                dict_block_status_->Convert(k), dict_block_status_->Convert(l), +                ostr); + +            string strKey; +            GenerateKey(pred->vec_items_[j - 1]->tree_item_, +                        pred->vec_items_[j]->tree_item_, k, l, strKey); + +            vector<double> vecOutput; +            srl_reorder_classifier_left_->fnEval(ostr.str().c_str(), vecOutput); +            (*map_srl_left_)[strKey] = vecOutput; + +            srl_reorder_classifier_right_->fnEval(ostr.str().c_str(), +                                                  vecOutput); +            (*map_srl_right_)[strKey] = vecOutput; +          } +        } +      } +    } +  } + +  double CalculateConstReorderProb( +      const Tsuruoka_Maxent* const_reorder_classifier, const MapClassifier* map, +      const string& key, const string& outcome) { +    MapClassifier::const_iterator iter = (*map).find(key); +    assert(iter != map->end()); +    int id = const_reorder_classifier->fnGetClassId(outcome); +    return iter->second[id]; +  } + +  void FreeSentenceVariables() { +    if (srl_sentence_ != NULL) { +      delete srl_sentence_; +      srl_sentence_ = NULL; +    } else { +      if (parsed_tree_ != NULL) delete parsed_tree_; +      parsed_tree_ = NULL; +    } + +    if (focused_consts_ != NULL) delete focused_consts_; +    focused_consts_ = NULL; + +    for (size_t i = 0; i < vec_target_tran_.size(); i++) +      delete vec_target_tran_[i]; +    vec_target_tran_.clear(); + +    if (map_left_ != NULL) delete map_left_; +    map_left_ = NULL; +    if (map_right_ != NULL) delete map_right_; +    map_right_ = NULL; + +    if (map_srl_left_ != NULL) delete map_srl_left_; +    map_srl_left_ = NULL; +    if (map_srl_right_ != NULL) delete map_srl_right_; +    map_srl_right_ = NULL; +  } + +  void InitializeClassifier(const char* pszFname, +                            Tsuruoka_Maxent** ppClassifier) { +    (*ppClassifier) = new Tsuruoka_Maxent(pszFname); +  } + +  void GenerateOutcome(const vector<int>& vecPos, vector<string>& vecOutcome) { +    vecOutcome.clear(); + +    for (size_t i = 1; i < vecPos.size(); i++) { +      if (vecPos[i] == -1 || vecPos[i] == vecPos[i - 1]) { +        vecOutcome.push_back("M");  // monotone +        continue; +      } + +      if (vecPos[i - 1] == -1) { +        // vecPos[i] is not -1 +        size_t j = i - 2; +        while (j > -1 && vecPos[j] == -1) j--; + +        size_t k; +        for (k = 0; k < j; k++) { +          if (vecPos[k] > vecPos[j] || vecPos[k] <= vecPos[i]) break; +        } +        if (k < j) { +          vecOutcome.push_back("DM"); +          continue; +        } + +        for (k = i + 1; k < vecPos.size(); k++) +          if (vecPos[k] < vecPos[i] && (j == -1 && vecPos[k] >= vecPos[j])) +            break; +        if (k < vecPos.size()) { +          vecOutcome.push_back("DM"); +          continue; +        } +        vecOutcome.push_back("M"); +      } else { +        // neither of vecPos[i-1] and vecPos[i] is -1 +        if (vecPos[i - 1] < vecPos[i]) { +          // monotone or discon't monotone +          size_t j; +          for (j = 0; j < i - 1; j++) +            if (vecPos[j] > vecPos[i - 1] && vecPos[j] <= vecPos[i]) break; +          if (j < i - 1) { +            vecOutcome.push_back("DM"); +            continue; +          } +          for (j = i + 1; j < vecPos.size(); j++) +            if (vecPos[j] >= vecPos[i - 1] && vecPos[j] < vecPos[i]) break; +          if (j < vecPos.size()) { +            vecOutcome.push_back("DM"); +            continue; +          } +          vecOutcome.push_back("M"); +        } else { +          // swap or discon't swap +          size_t j; +          for (j = 0; j < i - 1; j++) +            if (vecPos[j] > vecPos[i] && vecPos[j] <= vecPos[i - 1]) break; +          if (j < i - 1) { +            vecOutcome.push_back("DS"); +            continue; +          } +          for (j = i + 1; j < vecPos.size(); j++) +            if (vecPos[j] >= vecPos[i] && vecPos[j] < vecPos[i - 1]) break; +          if (j < vecPos.size()) { +            vecOutcome.push_back("DS"); +            continue; +          } +          vecOutcome.push_back("S"); +        } +      } +    } + +    assert(vecOutcome.size() == vecPos.size() - 1); +  } + +  void fnGetRelativePosition(const vector<int>& vecLeft, +                             vector<int>& vecPosition) { +    vecPosition.clear(); + +    vector<float> vec; +    vec.reserve(vecLeft.size()); +    for (size_t i = 0; i < vecLeft.size(); i++) { +      if (vecLeft[i] == -1) { +        if (i == 0) +          vec.push_back(-1); +        else +          vec.push_back(vecLeft[i - 1] + 0.1); +      } else +        vec.push_back(vecLeft[i]); +    } + +    for (size_t i = 0; i < vecLeft.size(); i++) { +      int count = 0; + +      for (size_t j = 0; j < vecLeft.size(); j++) { +        if (j == i) continue; +        if (vec[j] < vec[i]) { +          count++; +        } else if (vec[j] == vec[i] && j < i) { +          count++; +        } +      } +      vecPosition.push_back(count); +    } + +    for (size_t i = 1; i < vecPosition.size(); i++) { +      if (vecPosition[i - 1] == vecPosition[i]) { +        for (size_t j = 0; j < vecLeft.size(); j++) cout << vecLeft[j] << " "; +        cout << "\n"; +        assert(false); +      } +    } +  } + +  inline void fnGetOutcome(int i1, int i2, string& strOutcome) { +    assert(i1 != i2); +    if (i1 < i2) { +      if (i2 > i1 + 1) +        strOutcome = string("DM"); +      else +        strOutcome = string("M"); +    } else { +      if (i1 > i2 + 1) +        strOutcome = string("DS"); +      else +        strOutcome = string("S"); +    } +  } + +  // features in constituent_reorder_model.cc +  void GenerateFeature(const SParsedTree* pTree, const STreeItem* pParent, +                       int iPos, const string& strBlockStatus1, +                       const string& strBlockStatus2, ostringstream& ostr) { +    STreeItem* pCon1, *pCon2; +    pCon1 = pParent->m_vecChildren[iPos - 1]; +    pCon2 = pParent->m_vecChildren[iPos]; + +    string left_label = string(pCon1->m_pszTerm); +    string right_label = string(pCon2->m_pszTerm); +    string parent_label = string(pParent->m_pszTerm); + +    vector<string> vec_other_right_sibling; +    for (int i = iPos + 1; i < pParent->m_vecChildren.size(); i++) +      vec_other_right_sibling.push_back( +          string(pParent->m_vecChildren[i]->m_pszTerm)); +    if (vec_other_right_sibling.size() == 0) +      vec_other_right_sibling.push_back(string("NULL")); +    vector<string> vec_other_left_sibling; +    for (int i = 0; i < iPos - 1; i++) +      vec_other_left_sibling.push_back( +          string(pParent->m_vecChildren[i]->m_pszTerm)); +    if (vec_other_left_sibling.size() == 0) +      vec_other_left_sibling.push_back(string("NULL")); + +    // generate features +    // f1 +    ostr << "f1=" << left_label << "_" << right_label << "_" << parent_label; +    // f2 +    for (int i = 0; i < vec_other_right_sibling.size(); i++) +      ostr << " f2=" << left_label << "_" << right_label << "_" << parent_label +           << "_" << vec_other_right_sibling[i]; +    // f3 +    for (int i = 0; i < vec_other_left_sibling.size(); i++) +      ostr << " f3=" << left_label << "_" << right_label << "_" << parent_label +           << "_" << vec_other_left_sibling[i]; +    // f4 +    ostr << " f4=" << left_label << "_" << right_label << "_" +         << pTree->m_vecTerminals[pCon1->m_iHeadWord]->m_ptParent->m_pszTerm; +    // f5 +    ostr << " f5=" << left_label << "_" << right_label << "_" +         << pTree->m_vecTerminals[pCon1->m_iHeadWord]->m_pszTerm; +    // f6 +    ostr << " f6=" << left_label << "_" << right_label << "_" +         << pTree->m_vecTerminals[pCon2->m_iHeadWord]->m_ptParent->m_pszTerm; +    // f7 +    ostr << " f7=" << left_label << "_" << right_label << "_" +         << pTree->m_vecTerminals[pCon2->m_iHeadWord]->m_pszTerm; +    // f8 +    ostr << " f8=" << left_label << "_" << right_label << "_" +         << strBlockStatus1; +    // f9 +    ostr << " f9=" << left_label << "_" << right_label << "_" +         << strBlockStatus2; + +    // f10 +    ostr << " f10=" << left_label << "_" << parent_label; +    // f11 +    ostr << " f11=" << right_label << "_" << parent_label; +  } + +  SParsedTree* ReadParseTree(const std::string& parse_file) { +    SParseReader* reader = new SParseReader(parse_file.c_str(), false); +    SParsedTree* tree = reader->fnReadNextParseTree(); +    // assert(tree != NULL); +    delete reader; +    return tree; +  } + +  SSrlSentence* ReadSRLSentence(const std::string& srl_file) { +    SSrlSentenceReader* reader = new SSrlSentenceReader(srl_file.c_str()); +    SSrlSentence* srl = reader->fnReadNextSrlSentence(); +    // assert(srl != NULL); +    delete reader; +    return srl; +  } + + private: +  Tsuruoka_Maxent* const_reorder_classifier_left_; +  Tsuruoka_Maxent* const_reorder_classifier_right_; + +  Tsuruoka_Maxent* srl_reorder_classifier_left_; +  Tsuruoka_Maxent* srl_reorder_classifier_right_; + +  MapClassifier* map_left_; +  MapClassifier* map_right_; + +  MapClassifier* map_srl_left_; +  MapClassifier* map_srl_right_; + +  SParsedTree* parsed_tree_; +  FocusedConstituent* focused_consts_; +  vector<TargetTranslation*> vec_target_tran_; + +  bool b_order_feature_; +  bool b_block_feature_; + +  bool b_srl_block_feature_; +  bool b_srl_order_feature_; +  SSrlSentence* srl_sentence_; +  FocusedSRL* focused_srl_; + +  Dict* dict_block_status_; +}; + +ConstReorderFeature::ConstReorderFeature(const std::string& param) { +  pimpl_ = new ConstReorderFeatureImpl(param); +  SetStateSize(ConstReorderFeatureImpl::ReserveStateSize()); +  SetIgnoredStateSize(ConstReorderFeatureImpl::ReserveStateSize()); +  name_ = "ConstReorderFeature"; +} + +ConstReorderFeature::~ConstReorderFeature() {  // TODO +  delete pimpl_; +} + +void ConstReorderFeature::PrepareForInput(const SentenceMetadata& smeta) { +  string parse_file = smeta.GetSGMLValue("parse"); +  if (parse_file.empty()) { +    parse_file = smeta.GetSGMLValue("src_tree"); +  } +  string srl_file = smeta.GetSGMLValue("srl"); +  assert(!(parse_file == "" && srl_file == "")); + +  pimpl_->InitializeInputSentence(parse_file, srl_file); +} + +void ConstReorderFeature::TraversalFeaturesImpl( +    const SentenceMetadata& /* smeta */, const Hypergraph::Edge& edge, +    const vector<const void*>& ant_states, SparseVector<double>* features, +    SparseVector<double>* /*estimated_features*/, void* state) const { +  pimpl_->SetConstReorderFeature(edge, features, ant_states, state); +} + +string ConstReorderFeature::usage(bool show_params, bool show_details) { +  ostringstream out; +  out << "ConstReorderFeature"; +  if (show_params) { +    out << " model_file_prefix [const_block=1 const_order=1] [srl_block=0 " +           "srl_order=0]" +        << "\nParameters:\n" +        << "  const_{block,order}: enable/disable constituency constraints.\n" +        << "  src_{block,order}: enable/disable semantic role labeling " +           "constraints.\n"; +  } +  if (show_details) { +    out << "\n" +        << "Soft reordering constraint features from " +           "http://www.aclweb.org/anthology/P14-1106. To train the classifers, " +           "use utils/const_reorder_model_trainer for constituency reordering " +           "constraints and utils/argument_reorder_model_trainer for semantic " +           "role labeling reordering constraints.\n" +        << "Input segments should provide path to parse tree (resp. SRL parse) " +           "as \"parse\" (resp. \"srl\") properties.\n"; +  } +  return out.str(); +} + +boost::shared_ptr<FeatureFunction> CreateConstReorderModel( +    const std::string& param) { +  ConstReorderFeature* ret = new ConstReorderFeature(param); +  return boost::shared_ptr<FeatureFunction>(ret); +} diff --git a/decoder/ff_const_reorder.h b/decoder/ff_const_reorder.h new file mode 100644 index 00000000..a5be02d0 --- /dev/null +++ b/decoder/ff_const_reorder.h @@ -0,0 +1,43 @@ +/* + * ff_const_reorder.h + * + *  Created on: Jul 11, 2013 + *      Author: junhuili + */ + +#ifndef FF_CONST_REORDER_H_ +#define FF_CONST_REORDER_H_ + +#include "ff_factory.h" +#include "ff.h" + +struct ConstReorderFeatureImpl; + +// Soft reordering constraint features from +// http://www.aclweb.org/anthology/P14-1106. To train the classifers, +// use utils/const_reorder_model_trainer for constituency reordering +// constraints and utils/argument_reorder_model_trainer for SRL +// reordering constraints. +// +// Input segments should provide path to parse tree (resp. SRL parse) +// as "parse" (resp. "srl") properties. +class ConstReorderFeature : public FeatureFunction { + public: +  ConstReorderFeature(const std::string& param); +  ~ConstReorderFeature(); +  static std::string usage(bool param, bool verbose); + + protected: +  virtual void PrepareForInput(const SentenceMetadata& smeta); + +  virtual void TraversalFeaturesImpl( +      const SentenceMetadata& smeta, const HG::Edge& edge, +      const std::vector<const void*>& ant_contexts, +      SparseVector<double>* features, SparseVector<double>* estimated_features, +      void* out_context) const; + + private: +  ConstReorderFeatureImpl* pimpl_; +}; + +#endif /* FF_CONST_REORDER_H_ */ diff --git a/decoder/ff_const_reorder_common.h b/decoder/ff_const_reorder_common.h new file mode 100644 index 00000000..755fd948 --- /dev/null +++ b/decoder/ff_const_reorder_common.h @@ -0,0 +1,1348 @@ +#ifndef _FF_CONST_REORDER_COMMON_H +#define _FF_CONST_REORDER_COMMON_H + +#include <string> +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <string> +#include <sstream> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "maxent.h" +#include "stringlib.h" + +namespace const_reorder { + +struct STreeItem { +  STreeItem(const char *pszTerm) { +    m_pszTerm = new char[strlen(pszTerm) + 1]; +    strcpy(m_pszTerm, pszTerm); + +    m_ptParent = NULL; +    m_iBegin = -1; +    m_iEnd = -1; +    m_iHeadChild = -1; +    m_iHeadWord = -1; +    m_iBrotherIndex = -1; +  } +  ~STreeItem() { +    delete[] m_pszTerm; +    for (size_t i = 0; i < m_vecChildren.size(); i++) delete m_vecChildren[i]; +  } +  int fnAppend(STreeItem *ptChild) { +    m_vecChildren.push_back(ptChild); +    ptChild->m_iBrotherIndex = m_vecChildren.size() - 1; +    ptChild->m_ptParent = this; +    return m_vecChildren.size() - 1; +  } +  int fnGetChildrenNum() { return m_vecChildren.size(); } + +  bool fnIsPreTerminal(void) { +    int I; +    if (this == NULL || m_vecChildren.size() == 0) return false; + +    for (I = 0; I < m_vecChildren.size(); I++) +      if (m_vecChildren[I]->m_vecChildren.size() > 0) return false; + +    return true; +  } + + public: +  char *m_pszTerm; + +  std::vector<STreeItem *> m_vecChildren;  // children items +  STreeItem *m_ptParent;                   // the parent item + +  int m_iBegin; +  int m_iEnd;           // the node span words[m_iBegin, m_iEnd] +  int m_iHeadChild;     // the index of its head child +  int m_iHeadWord;      // the index of its head word +  int m_iBrotherIndex;  // the index in his brothers +}; + +struct SGetHeadWord { +  typedef std::vector<std::string> CVectorStr; +  SGetHeadWord() {} +  ~SGetHeadWord() {} +  int fnGetHeadWord(char *pszCFGLeft, CVectorStr vectRight) { +    // 0 indicating from right to left while 1 indicating from left to right +    char szaHeadLists[201] = "0"; + +    /*  //head rules for Egnlish +    if( strcmp( pszCFGLeft, "ADJP" ) == 0 ) +            strcpy( szaHeadLists, "0NNS 0QP 0NN 0$ 0ADVP 0JJ 0VBN 0VBG 0ADJP +    0JJR 0NP 0JJS 0DT 0FW 0RBR 0RBS 0SBAR 0RB 0" ); +    else if( strcmp( pszCFGLeft, "ADVP" ) == 0 ) +            strcpy( szaHeadLists, "1RB 1RBR 1RBS 1FW 1ADVP 1TO 1CD 1JJR 1JJ 1IN +    1NP 1JJS 1NN 1" ); +    else if( strcmp( pszCFGLeft, "CONJP" ) == 0 ) +            strcpy( szaHeadLists, "1CC 1RB 1IN 1" ); +    else if( strcmp( pszCFGLeft, "FRAG" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "INTJ" ) == 0 ) +            strcpy( szaHeadLists, "0" ); +    else if( strcmp( pszCFGLeft, "LST" ) == 0 ) +            strcpy( szaHeadLists, "1LS 1: 1CLN 1" ); +    else if( strcmp( pszCFGLeft, "NAC" ) == 0 ) +            strcpy( szaHeadLists, "0NN 0NNS 0NNP 0NNPS 0NP 0NAC 0EX 0$ 0CD 0QP +    0PRP 0VBG 0JJ 0JJS 0JJR 0ADJP 0FW 0" ); +    else if( strcmp( pszCFGLeft, "PP" ) == 0 ) +            strcpy( szaHeadLists, "1IN 1TO 1VBG 1VBN 1RP 1FW 1" ); +    else if( strcmp( pszCFGLeft, "PRN" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "PRT" ) == 0 ) +            strcpy( szaHeadLists, "1RP 1" ); +    else if( strcmp( pszCFGLeft, "QP" ) == 0 ) +            strcpy( szaHeadLists, "0$ 0IN 0NNS 0NN 0JJ 0RB 0DT 0CD 0NCD 0QP 0JJR +    0JJS 0" ); +    else if( strcmp( pszCFGLeft, "RRC" ) == 0 ) +            strcpy( szaHeadLists, "1VP 1NP 1ADVP 1ADJP 1PP 1" ); +    else if( strcmp( pszCFGLeft, "S" ) == 0 ) +            strcpy( szaHeadLists, "0TO 0IN 0VP 0S 0SBAR 0ADJP 0UCP 0NP 0" ); +    else if( strcmp( pszCFGLeft, "SBAR" ) == 0 ) +            strcpy( szaHeadLists, "0WHNP 0WHPP 0WHADVP 0WHADJP 0IN 0DT 0S 0SQ +    0SINV 0SBAR 0FRAG 0" ); +    else if( strcmp( pszCFGLeft, "SBARQ" ) == 0 ) +            strcpy( szaHeadLists, "0SQ 0S 0SINV 0SBARQ 0FRAG 0" ); +    else if( strcmp( pszCFGLeft, "SINV" ) == 0 ) +            strcpy( szaHeadLists, "0VBZ 0VBD 0VBP 0VB 0MD 0VP 0S 0SINV 0ADJP 0NP +    0" ); +    else if( strcmp( pszCFGLeft, "SQ" ) == 0 ) +            strcpy( szaHeadLists, "0VBZ 0VBD 0VBP 0VB 0MD 0VP 0SQ 0" ); +    else if( strcmp( pszCFGLeft, "UCP" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "VP" ) == 0 ) +            strcpy( szaHeadLists, "0TO 0VBD 0VBN 0MD 0VBZ 0VB 0VBG 0VBP 0VP +    0ADJP 0NN 0NNS 0NP 0" ); +    else if( strcmp( pszCFGLeft, "WHADJP" ) == 0 ) +            strcpy( szaHeadLists, "0CC 0WRB 0JJ 0ADJP 0" ); +    else if( strcmp( pszCFGLeft, "WHADVP" ) == 0 ) +            strcpy( szaHeadLists, "1CC 1WRB 1" ); +    else if( strcmp( pszCFGLeft, "WHNP" ) == 0 ) +            strcpy( szaHeadLists, "0WDT 0WP 0WP$ 0WHADJP 0WHPP 0WHNP 0" ); +    else if( strcmp( pszCFGLeft, "WHPP" ) == 0 ) +            strcpy( szaHeadLists, "1IN 1TO FW 1" ); +    else if( strcmp( pszCFGLeft, "NP" ) == 0 ) +            strcpy( szaHeadLists, "0NN NNP NNS NNPS NX POS JJR 0NP 0$ ADJP PRN +    0CD 0JJ JJS RB QP 0" ); +    */ + +    if (strcmp(pszCFGLeft, "ADJP") == 0) +      strcpy(szaHeadLists, "0ADJP JJ 0AD NN CS 0"); +    else if (strcmp(pszCFGLeft, "ADVP") == 0) +      strcpy(szaHeadLists, "0ADVP AD 0"); +    else if (strcmp(pszCFGLeft, "CLP") == 0) +      strcpy(szaHeadLists, "0CLP M 0"); +    else if (strcmp(pszCFGLeft, "CP") == 0) +      strcpy(szaHeadLists, "0DEC SP 1ADVP CS 0CP IP 0"); +    else if (strcmp(pszCFGLeft, "DNP") == 0) +      strcpy(szaHeadLists, "0DNP DEG 0DEC 0"); +    else if (strcmp(pszCFGLeft, "DVP") == 0) +      strcpy(szaHeadLists, "0DVP DEV 0"); +    else if (strcmp(pszCFGLeft, "DP") == 0) +      strcpy(szaHeadLists, "1DP DT 1"); +    else if (strcmp(pszCFGLeft, "FRAG") == 0) +      strcpy(szaHeadLists, "0VV NR NN 0"); +    else if (strcmp(pszCFGLeft, "INTJ") == 0) +      strcpy(szaHeadLists, "0INTJ IJ 0"); +    else if (strcmp(pszCFGLeft, "LST") == 0) +      strcpy(szaHeadLists, "1LST CD OD 1"); +    else if (strcmp(pszCFGLeft, "IP") == 0) +      strcpy(szaHeadLists, "0IP VP 0VV 0"); +    // strcpy( szaHeadLists, "0VP 0VV 1IP 0" ); +    else if (strcmp(pszCFGLeft, "LCP") == 0) +      strcpy(szaHeadLists, "0LCP LC 0"); +    else if (strcmp(pszCFGLeft, "NP") == 0) +      strcpy(szaHeadLists, "0NP NN NT NR QP 0"); +    else if (strcmp(pszCFGLeft, "PP") == 0) +      strcpy(szaHeadLists, "1PP P 1"); +    else if (strcmp(pszCFGLeft, "PRN") == 0) +      strcpy(szaHeadLists, "0 NP IP VP NT NR NN 0"); +    else if (strcmp(pszCFGLeft, "QP") == 0) +      strcpy(szaHeadLists, "0QP CLP CD OD 0"); +    else if (strcmp(pszCFGLeft, "VP") == 0) +      strcpy(szaHeadLists, "1VP VA VC VE VV BA LB VCD VSB VRD VNV VCP 1"); +    else if (strcmp(pszCFGLeft, "VCD") == 0) +      strcpy(szaHeadLists, "0VCD VV VA VC VE 0"); +    if (strcmp(pszCFGLeft, "VRD") == 0) +      strcpy(szaHeadLists, "0VRD VV VA VC VE 0"); +    else if (strcmp(pszCFGLeft, "VSB") == 0) +      strcpy(szaHeadLists, "0VSB VV VA VC VE 0"); +    else if (strcmp(pszCFGLeft, "VCP") == 0) +      strcpy(szaHeadLists, "0VCP VV VA VC VE 0"); +    else if (strcmp(pszCFGLeft, "VNV") == 0) +      strcpy(szaHeadLists, "0VNV VV VA VC VE 0"); +    else if (strcmp(pszCFGLeft, "VPT") == 0) +      strcpy(szaHeadLists, "0VNV VV VA VC VE 0"); +    else if (strcmp(pszCFGLeft, "UCP") == 0) +      strcpy(szaHeadLists, "0"); +    else if (strcmp(pszCFGLeft, "WHNP") == 0) +      strcpy(szaHeadLists, "0WHNP NP NN NT NR QP 0"); +    else if (strcmp(pszCFGLeft, "WHPP") == 0) +      strcpy(szaHeadLists, "1WHPP PP P 1"); + +    /*  //head rules for GENIA corpus +    if( strcmp( pszCFGLeft, "ADJP" ) == 0 ) +            strcpy( szaHeadLists, "0NNS 0QP 0NN 0$ 0ADVP 0JJ 0VBN 0VBG 0ADJP +    0JJR 0NP 0JJS 0DT 0FW 0RBR 0RBS 0SBAR 0RB 0" ); +    else if( strcmp( pszCFGLeft, "ADVP" ) == 0 ) +            strcpy( szaHeadLists, "1RB 1RBR 1RBS 1FW 1ADVP 1TO 1CD 1JJR 1JJ 1IN +    1NP 1JJS 1NN 1" ); +    else if( strcmp( pszCFGLeft, "CONJP" ) == 0 ) +            strcpy( szaHeadLists, "1CC 1RB 1IN 1" ); +    else if( strcmp( pszCFGLeft, "FRAG" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "INTJ" ) == 0 ) +            strcpy( szaHeadLists, "0" ); +    else if( strcmp( pszCFGLeft, "LST" ) == 0 ) +            strcpy( szaHeadLists, "1LS 1: 1CLN 1" ); +    else if( strcmp( pszCFGLeft, "NAC" ) == 0 ) +            strcpy( szaHeadLists, "0NN 0NNS 0NNP 0NNPS 0NP 0NAC 0EX 0$ 0CD 0QP +    0PRP 0VBG 0JJ 0JJS 0JJR 0ADJP 0FW 0" ); +    else if( strcmp( pszCFGLeft, "PP" ) == 0 ) +            strcpy( szaHeadLists, "1IN 1TO 1VBG 1VBN 1RP 1FW 1" ); +    else if( strcmp( pszCFGLeft, "PRN" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "PRT" ) == 0 ) +            strcpy( szaHeadLists, "1RP 1" ); +    else if( strcmp( pszCFGLeft, "QP" ) == 0 ) +            strcpy( szaHeadLists, "0$ 0IN 0NNS 0NN 0JJ 0RB 0DT 0CD 0NCD 0QP 0JJR +    0JJS 0" ); +    else if( strcmp( pszCFGLeft, "RRC" ) == 0 ) +            strcpy( szaHeadLists, "1VP 1NP 1ADVP 1ADJP 1PP 1" ); +    else if( strcmp( pszCFGLeft, "S" ) == 0 ) +            strcpy( szaHeadLists, "0TO 0IN 0VP 0S 0SBAR 0ADJP 0UCP 0NP 0" ); +    else if( strcmp( pszCFGLeft, "SBAR" ) == 0 ) +            strcpy( szaHeadLists, "0WHNP 0WHPP 0WHADVP 0WHADJP 0IN 0DT 0S 0SQ +    0SINV 0SBAR 0FRAG 0" ); +    else if( strcmp( pszCFGLeft, "SBARQ" ) == 0 ) +            strcpy( szaHeadLists, "0SQ 0S 0SINV 0SBARQ 0FRAG 0" ); +    else if( strcmp( pszCFGLeft, "SINV" ) == 0 ) +            strcpy( szaHeadLists, "0VBZ 0VBD 0VBP 0VB 0MD 0VP 0S 0SINV 0ADJP 0NP +    0" ); +    else if( strcmp( pszCFGLeft, "SQ" ) == 0 ) +            strcpy( szaHeadLists, "0VBZ 0VBD 0VBP 0VB 0MD 0VP 0SQ 0" ); +    else if( strcmp( pszCFGLeft, "UCP" ) == 0 ) +            strcpy( szaHeadLists, "1" ); +    else if( strcmp( pszCFGLeft, "VP" ) == 0 ) +            strcpy( szaHeadLists, "0TO 0VBD 0VBN 0MD 0VBZ 0VB 0VBG 0VBP 0VP +    0ADJP 0NN 0NNS 0NP 0" ); +    else if( strcmp( pszCFGLeft, "WHADJP" ) == 0 ) +            strcpy( szaHeadLists, "0CC 0WRB 0JJ 0ADJP 0" ); +    else if( strcmp( pszCFGLeft, "WHADVP" ) == 0 ) +            strcpy( szaHeadLists, "1CC 1WRB 1" ); +    else if( strcmp( pszCFGLeft, "WHNP" ) == 0 ) +            strcpy( szaHeadLists, "0WDT 0WP 0WP$ 0WHADJP 0WHPP 0WHNP 0" ); +    else if( strcmp( pszCFGLeft, "WHPP" ) == 0 ) +            strcpy( szaHeadLists, "1IN 1TO FW 1" ); +    else if( strcmp( pszCFGLeft, "NP" ) == 0 ) +            strcpy( szaHeadLists, "0NN NNP NNS NNPS NX POS JJR 0NP 0$ ADJP PRN +    0CD 0JJ JJS RB QP 0" ); +    */ + +    return fnMyOwnHeadWordRule(szaHeadLists, vectRight); +  } + + private: +  int fnMyOwnHeadWordRule(char *pszaHeadLists, CVectorStr vectRight) { +    char szHeadList[201], *p; +    char szTerm[101]; +    int J; + +    p = pszaHeadLists; + +    int iCountRight; + +    iCountRight = vectRight.size(); + +    szHeadList[0] = '\0'; +    while (1) { +      szTerm[0] = '\0'; +      sscanf(p, "%s", szTerm); +      if (strlen(szHeadList) == 0) { +        if (strcmp(szTerm, "0") == 0) { +          return iCountRight - 1; +        } +        if (strcmp(szTerm, "1") == 0) { +          return 0; +        } + +        sprintf(szHeadList, "%c %s ", szTerm[0], szTerm + 1); +        p = strstr(p, szTerm); +        p += strlen(szTerm); +      } else { +        if ((szTerm[0] == '0') || (szTerm[0] == '1')) { +          if (szHeadList[0] == '0') { +            for (J = iCountRight - 1; J >= 0; J--) { +              sprintf(szTerm, " %s ", vectRight.at(J).c_str()); +              if (strstr(szHeadList, szTerm) != NULL) return J; +            } +          } else { +            for (J = 0; J < iCountRight; J++) { +              sprintf(szTerm, " %s ", vectRight.at(J).c_str()); +              if (strstr(szHeadList, szTerm) != NULL) return J; +            } +          } + +          szHeadList[0] = '\0'; +        } else { +          strcat(szHeadList, szTerm); +          strcat(szHeadList, " "); + +          p = strstr(p, szTerm); +          p += strlen(szTerm); +        } +      } +    } + +    return 0; +  } +}; + +struct SParsedTree { +  SParsedTree() { m_ptRoot = NULL; } +  ~SParsedTree() { +    if (m_ptRoot != NULL) delete m_ptRoot; +  } +  static SParsedTree *fnConvertFromString(const char *pszStr) { +    if (strcmp(pszStr, "(())") == 0) return NULL; +    SParsedTree *pTree = new SParsedTree(); + +    std::vector<std::string> vecSyn; +    fnReadSyntactic(pszStr, vecSyn); + +    int iLeft = 1, iRight = 1;  //# left/right parenthesis + +    STreeItem *pcurrent; + +    pTree->m_ptRoot = new STreeItem(vecSyn[1].c_str()); + +    pcurrent = pTree->m_ptRoot; + +    for (size_t i = 2; i < vecSyn.size() - 1; i++) { +      if (strcmp(vecSyn[i].c_str(), "(") == 0) +        iLeft++; +      else if (strcmp(vecSyn[i].c_str(), ")") == 0) { +        iRight++; +        if (pcurrent == NULL) { +          // error +          fprintf(stderr, "ERROR in ConvertFromString\n"); +          fprintf(stderr, "%s\n", pszStr); +          return NULL; +        } +        pcurrent = pcurrent->m_ptParent; +      } else { +        STreeItem *ptNewItem = new STreeItem(vecSyn[i].c_str()); +        pcurrent->fnAppend(ptNewItem); +        pcurrent = ptNewItem; + +        if (strcmp(vecSyn[i - 1].c_str(), "(") != 0 && +            strcmp(vecSyn[i - 1].c_str(), ")") != 0) { +          pTree->m_vecTerminals.push_back(ptNewItem); +          pcurrent = pcurrent->m_ptParent; +        } +      } +    } + +    if (iLeft != iRight) { +      // error +      fprintf(stderr, "the left and right parentheses are not matched!"); +      fprintf(stderr, "ERROR in ConvertFromString\n"); +      fprintf(stderr, "%s\n", pszStr); +      return NULL; +    } + +    return pTree; +  } + +  int fnGetNumWord() { return m_vecTerminals.size(); } + +  void fnSetSpanInfo() { +    int iNextNum = 0; +    fnSuffixTraverseSetSpanInfo(m_ptRoot, iNextNum); +  } + +  void fnSetHeadWord() { +    for (size_t i = 0; i < m_vecTerminals.size(); i++) +      m_vecTerminals[i]->m_iHeadWord = i; +    SGetHeadWord *pGetHeadWord = new SGetHeadWord(); +    fnSuffixTraverseSetHeadWord(m_ptRoot, pGetHeadWord); +    delete pGetHeadWord; +  } + +  STreeItem *fnFindNodeForSpan(int iLeft, int iRight, bool bLowest) { +    STreeItem *pTreeItem = m_vecTerminals[iLeft]; + +    while (pTreeItem->m_iEnd < iRight) { +      pTreeItem = pTreeItem->m_ptParent; +      if (pTreeItem == NULL) break; +    } +    if (pTreeItem == NULL) return NULL; +    if (pTreeItem->m_iEnd > iRight) return NULL; + +    assert(pTreeItem->m_iEnd == iRight); +    if (bLowest) return pTreeItem; + +    while (pTreeItem->m_ptParent != NULL && +           pTreeItem->m_ptParent->fnGetChildrenNum() == 1) +      pTreeItem = pTreeItem->m_ptParent; + +    return pTreeItem; +  } + + private: +  void fnSuffixTraverseSetSpanInfo(STreeItem *ptItem, int &iNextNum) { +    int I; +    int iNumChildren = ptItem->fnGetChildrenNum(); +    for (I = 0; I < iNumChildren; I++) +      fnSuffixTraverseSetSpanInfo(ptItem->m_vecChildren[I], iNextNum); + +    if (I == 0) { +      ptItem->m_iBegin = iNextNum; +      ptItem->m_iEnd = iNextNum++; +    } else { +      ptItem->m_iBegin = ptItem->m_vecChildren[0]->m_iBegin; +      ptItem->m_iEnd = ptItem->m_vecChildren[I - 1]->m_iEnd; +    } +  } + +  void fnSuffixTraverseSetHeadWord(STreeItem *ptItem, +                                   SGetHeadWord *pGetHeadWord) { +    int I, iHeadchild; + +    if (ptItem->m_vecChildren.size() == 0) return; + +    for (I = 0; I < ptItem->m_vecChildren.size(); I++) +      fnSuffixTraverseSetHeadWord(ptItem->m_vecChildren[I], pGetHeadWord); + +    std::vector<std::string> vecRight; + +    if (ptItem->m_vecChildren.size() == 1) +      iHeadchild = 0; +    else { +      for (I = 0; I < ptItem->m_vecChildren.size(); I++) +        vecRight.push_back(std::string(ptItem->m_vecChildren[I]->m_pszTerm)); + +      iHeadchild = pGetHeadWord->fnGetHeadWord(ptItem->m_pszTerm, vecRight); +    } + +    ptItem->m_iHeadChild = iHeadchild; +    ptItem->m_iHeadWord = ptItem->m_vecChildren[iHeadchild]->m_iHeadWord; +  } + +  static void fnReadSyntactic(const char *pszSyn, +                              std::vector<std::string> &vec) { +    char *p; +    int I; + +    int iLeftNum, iRightNum; +    char *pszTmp, *pszTerm; +    pszTmp = new char[strlen(pszSyn)]; +    pszTerm = new char[strlen(pszSyn)]; +    pszTmp[0] = pszTerm[0] = '\0'; + +    vec.clear(); + +    char *pszLine; +    pszLine = new char[strlen(pszSyn) + 1]; +    strcpy(pszLine, pszSyn); + +    char *pszLine2; + +    while (1) { +      while ((strlen(pszLine) > 0) && (pszLine[strlen(pszLine) - 1] > 0) && +             (pszLine[strlen(pszLine) - 1] <= ' ')) +        pszLine[strlen(pszLine) - 1] = '\0'; + +      if (strlen(pszLine) == 0) break; + +      // printf( "%s\n", pszLine ); +      pszLine2 = pszLine; +      while (pszLine2[0] <= ' ') pszLine2++; +      if (pszLine2[0] == '<') continue; + +      sscanf(pszLine2 + 1, "%s", pszTmp); + +      if (pszLine2[0] == '(') { +        iLeftNum = 0; +        iRightNum = 0; +      } + +      p = pszLine2; +      while (1) { +        pszTerm[0] = '\0'; +        sscanf(p, "%s", pszTerm); + +        if (strlen(pszTerm) == 0) break; +        p = strstr(p, pszTerm); +        p += strlen(pszTerm); + +        if ((pszTerm[0] == '(') || (pszTerm[strlen(pszTerm) - 1] == ')')) { +          if (pszTerm[0] == '(') { +            vec.push_back(std::string("(")); +            iLeftNum++; + +            I = 1; +            while (pszTerm[I] == '(' && pszTerm[I] != '\0') { +              vec.push_back(std::string("(")); +              iLeftNum++; + +              I++; +            } + +            if (strlen(pszTerm) > 1) vec.push_back(std::string(pszTerm + I)); +          } else { +            char *pTmp; +            pTmp = pszTerm + strlen(pszTerm) - 1; +            while ((pTmp[0] == ')') && (pTmp >= pszTerm)) pTmp--; +            pTmp[1] = '\0'; + +            if (strlen(pszTerm) > 0) vec.push_back(std::string(pszTerm)); +            pTmp += 2; + +            for (I = 0; I <= (int)strlen(pTmp); I++) { +              vec.push_back(std::string(")")); +              iRightNum++; +            } +          } +        } else { +          char *q; +          q = strchr(pszTerm, ')'); +          if (q != NULL) { +            q[0] = '\0'; +            if (pszTerm[0] != '\0') vec.push_back(std::string(pszTerm)); +            vec.push_back(std::string(")")); +            iRightNum++; + +            q++; +            while (q[0] == ')') { +              vec.push_back(std::string(")")); +              q++; +              iRightNum++; +            } + +            while (q[0] == '(') { +              vec.push_back(std::string("(")); +              q++; +              iLeftNum++; +            } + +            if (q[0] != '\0') vec.push_back(std::string(q)); +          } else +            vec.push_back(std::string(pszTerm)); +        } +      } + +      if (iLeftNum != iRightNum) { +        fprintf(stderr, "%s\n", pszSyn); +        assert(iLeftNum == iRightNum); +      } +      /*if ( iLeftNum != iRightNum ) { +              printf( "ERROR: left( and right ) is not matched, %d ( and %d +      )\n", iLeftNum, iRightNum ); +              return; +      }*/ + +      if (vec.size() >= 2 && strcmp(vec[1].c_str(), "(") == 0) { +        //( (IP..) ) +        std::vector<std::string>::iterator it; +        it = vec.begin(); +        it++; +        vec.insert(it, std::string("ROOT")); +      } + +      break; +    } + +    delete[] pszLine; +    delete[] pszTmp; +    delete[] pszTerm; +  } + + public: +  STreeItem *m_ptRoot; +  std::vector<STreeItem *> m_vecTerminals;  // the leaf nodes +}; + +struct SParseReader { +  SParseReader(const char *pszParse_Fname, bool bFlattened = false) +      : m_bFlattened(bFlattened) { +    m_fpIn = fopen(pszParse_Fname, "r"); +    assert(m_fpIn != NULL); +  } +  ~SParseReader() { +    if (m_fpIn != NULL) fclose(m_fpIn); +  } + +  SParsedTree *fnReadNextParseTree() { +    SParsedTree *pTree = NULL; +    char *pszLine = new char[100001]; +    int iLen; + +    while (fnReadNextSentence(pszLine, &iLen) == true) { +      if (iLen == 0) continue; + +      pTree = SParsedTree::fnConvertFromString(pszLine); +      if (pTree == NULL) break; +      if (m_bFlattened) +        fnPostProcessingFlattenedParse(pTree); +      else { +        pTree->fnSetSpanInfo(); +        pTree->fnSetHeadWord(); +      } +      break; +    } + +    delete[] pszLine; +    return pTree; +  } + +  SParsedTree *fnReadNextParseTreeWithProb(double *pProb) { +    SParsedTree *pTree = NULL; +    char *pszLine = new char[100001]; +    int iLen; + +    while (fnReadNextSentence(pszLine, &iLen) == true) { +      if (iLen == 0) continue; + +      char *p = strchr(pszLine, ' '); +      assert(p != NULL); +      p[0] = '\0'; +      p++; +      if (pProb) (*pProb) = atof(pszLine); + +      pTree = SParsedTree::fnConvertFromString(p); +      if (m_bFlattened) +        fnPostProcessingFlattenedParse(pTree); +      else { +        pTree->fnSetSpanInfo(); +        pTree->fnSetHeadWord(); +      } +      break; +    } + +    delete[] pszLine; +    return pTree; +  } + + private: +  /* +   * since to the parse tree is a flattened tree, use the head mark to identify +   * head info. +   * the head node will be marked as "*XP*" +   */ +  void fnSetParseTreeHeadInfo(SParsedTree *pTree) { +    for (size_t i = 0; i < pTree->m_vecTerminals.size(); i++) +      pTree->m_vecTerminals[i]->m_iHeadWord = i; +    fnSuffixTraverseSetHeadWord(pTree->m_ptRoot); +  } + +  void fnSuffixTraverseSetHeadWord(STreeItem *pTreeItem) { +    if (pTreeItem->m_vecChildren.size() == 0) return; + +    for (size_t i = 0; i < pTreeItem->m_vecChildren.size(); i++) +      fnSuffixTraverseSetHeadWord(pTreeItem->m_vecChildren[i]); + +    std::vector<std::string> vecRight; + +    int iHeadchild; + +    if (pTreeItem->fnIsPreTerminal()) { +      iHeadchild = 0; +    } else { +      size_t i; +      for (i = 0; i < pTreeItem->m_vecChildren.size(); i++) { +        char *p = pTreeItem->m_vecChildren[i]->m_pszTerm; +        if (p[0] == '*' && p[strlen(p) - 1] == '*') { +          iHeadchild = i; +          p[strlen(p) - 1] = '\0'; +          std::string str = p + 1; +          strcpy(p, str.c_str());  // erase the "*..*" +          break; +        } +      } +      assert(i < pTreeItem->m_vecChildren.size()); +    } + +    pTreeItem->m_iHeadChild = iHeadchild; +    pTreeItem->m_iHeadWord = pTreeItem->m_vecChildren[iHeadchild]->m_iHeadWord; +  } +  void fnPostProcessingFlattenedParse(SParsedTree *pTree) { +    pTree->fnSetSpanInfo(); +    fnSetParseTreeHeadInfo(pTree); +  } +  bool fnReadNextSentence(char *pszLine, int *piLength) { +    if (feof(m_fpIn) == true) return false; + +    int iLen; + +    pszLine[0] = '\0'; + +    fgets(pszLine, 10001, m_fpIn); +    iLen = strlen(pszLine); +    while (iLen > 0 && pszLine[iLen - 1] > 0 && pszLine[iLen - 1] < 33) { +      pszLine[iLen - 1] = '\0'; +      iLen--; +    } + +    if (piLength != NULL) (*piLength) = iLen; + +    return true; +  } + + private: +  FILE *m_fpIn; +  const bool m_bFlattened; +}; + +/* + * Note: + *      m_vec_s_align.size() may not be equal to the length of source side + *sentence + *                           due to the last words may not be aligned + * + */ +struct SAlignment { +  typedef std::vector<int> SingleAlign; +  SAlignment(const char* pszAlign) { fnInitializeAlignment(pszAlign); } +  ~SAlignment() {} + +  bool fnIsAligned(int i, bool s) const { +    const std::vector<SingleAlign>* palign; +    if (s == true) +      palign = &m_vec_s_align; +    else +      palign = &m_vec_t_align; +    if ((*palign)[i].size() == 0) return false; +    return true; +  } + +  /* +   * return true if [b, e] is aligned phrases on source side (if s==true) or on +   * the target side (if s==false); +   * return false, otherwise. +   */ +  bool fnIsAlignedPhrase(int b, int e, bool s, int* pob, int* poe) const { +    int ob, oe;  //[b, e] on the other side +    if (s == true) +      fnGetLeftRightMost(b, e, m_vec_s_align, ob, oe); +    else +      fnGetLeftRightMost(b, e, m_vec_t_align, ob, oe); + +    if (ob == -1) { +      if (pob != NULL) (*pob) = -1; +      if (poe != NULL) (*poe) = -1; +      return false;  // no aligned word among [b, e] +    } +    if (pob != NULL) (*pob) = ob; +    if (poe != NULL) (*poe) = oe; + +    int bb, be;  //[b, e] back given [ob, oe] on the other side +    if (s == true) +      fnGetLeftRightMost(ob, oe, m_vec_t_align, bb, be); +    else +      fnGetLeftRightMost(ob, oe, m_vec_s_align, bb, be); + +    if (bb < b || be > e) return false; +    return true; +  } + +  bool fnIsAlignedTightPhrase(int b, int e, bool s, int* pob, int* poe) const { +    const std::vector<SingleAlign>* palign; +    if (s == true) +      palign = &m_vec_s_align; +    else +      palign = &m_vec_t_align; + +    if ((*palign).size() <= e || (*palign)[b].size() == 0 || +        (*palign)[e].size() == 0) +      return false; + +    return fnIsAlignedPhrase(b, e, s, pob, poe); +  } + +  void fnGetLeftRightMost(int b, int e, bool s, int& ob, int& oe) const { +    if (s == true) +      fnGetLeftRightMost(b, e, m_vec_s_align, ob, oe); +    else +      fnGetLeftRightMost(b, e, m_vec_t_align, ob, oe); +  } + +  /* +   * look the translation of source[b, e] is continuous or not +   * 1) return "Unaligned": if the source[b, e] is translated silently; +   * 2) return "Con't": if none of target words in target[.., ..] is exclusively +   * aligned to any word outside source[b, e] +   * 3) return "Discon't": otherwise; +   */ +  std::string fnIsContinuous(int b, int e) const { +    int ob, oe; +    fnGetLeftRightMost(b, e, true, ob, oe); +    if (ob == -1) return "Unaligned"; + +    for (int i = ob; i <= oe; i++) { +      if (!fnIsAligned(i, false)) continue; +      const SingleAlign& a = m_vec_t_align[i]; +      int j; +      for (j = 0; j < a.size(); j++) +        if (a[j] >= b && a[j] <= e) break; +      if (j == a.size()) return "Discon't"; +    } +    return "Con't"; +  } + +  const SingleAlign* fnGetSingleWordAlign(int i, bool s) const { +    if (s == true) { +      if (i >= m_vec_s_align.size()) return NULL; +      return &(m_vec_s_align[i]); +    } else { +      if (i >= m_vec_t_align.size()) return NULL; +      return &(m_vec_t_align[i]); +    } +  } + + private: +  void fnGetLeftRightMost(int b, int e, const std::vector<SingleAlign>& align, +                          int& ob, int& oe) const { +    ob = oe = -1; +    for (int i = b; i <= e && i < align.size(); i++) { +      if (align[i].size() > 0) { +        if (align[i][0] < ob || ob == -1) ob = align[i][0]; +        if (oe < align[i][align[i].size() - 1]) +          oe = align[i][align[i].size() - 1]; +      } +    } +  } +  void fnInitializeAlignment(const char* pszAlign) { +    m_vec_s_align.clear(); +    m_vec_t_align.clear(); + +    std::vector<std::string> terms = SplitOnWhitespace(std::string(pszAlign)); +    int si, ti; +    for (size_t i = 0; i < terms.size(); i++) { +      sscanf(terms[i].c_str(), "%d-%d", &si, &ti); + +      while (m_vec_s_align.size() <= si) { +        SingleAlign sa; +        m_vec_s_align.push_back(sa); +      } +      while (m_vec_t_align.size() <= ti) { +        SingleAlign sa; +        m_vec_t_align.push_back(sa); +      } + +      m_vec_s_align[si].push_back(ti); +      m_vec_t_align[ti].push_back(si); +    } + +    // sort +    for (size_t i = 0; i < m_vec_s_align.size(); i++) { +      std::sort(m_vec_s_align[i].begin(), m_vec_s_align[i].end()); +    } +    for (size_t i = 0; i < m_vec_t_align.size(); i++) { +      std::sort(m_vec_t_align[i].begin(), m_vec_t_align[i].end()); +    } +  } + + private: +  std::vector<SingleAlign> m_vec_s_align;  // source side words' alignment +  std::vector<SingleAlign> m_vec_t_align;  // target side words' alignment +}; + +struct SAlignmentReader { +  SAlignmentReader(const char* pszFname) { +    m_fpIn = fopen(pszFname, "r"); +    assert(m_fpIn != NULL); +  } +  ~SAlignmentReader() { +    if (m_fpIn != NULL) fclose(m_fpIn); +  } +  SAlignment* fnReadNextAlignment() { +    if (feof(m_fpIn) == true) return NULL; +    char* pszLine = new char[100001]; +    pszLine[0] = '\0'; +    fgets(pszLine, 10001, m_fpIn); +    int iLen = strlen(pszLine); +    if (iLen == 0) return NULL; +    while (iLen > 0 && pszLine[iLen - 1] > 0 && pszLine[iLen - 1] < 33) { +      pszLine[iLen - 1] = '\0'; +      iLen--; +    } +    SAlignment* pAlign = new SAlignment(pszLine); +    delete[] pszLine; +    return pAlign; +  } + + private: +  FILE* m_fpIn; +}; + +struct SArgument { +  SArgument(const char* pszRole, int iBegin, int iEnd, float fProb) { +    m_pszRole = new char[strlen(pszRole) + 1]; +    strcpy(m_pszRole, pszRole); +    m_iBegin = iBegin; +    m_iEnd = iEnd; +    m_fProb = fProb; +    m_pTreeItem = NULL; +  } +  ~SArgument() { delete[] m_pszRole; } + +  void fnSetTreeItem(STreeItem* pTreeItem) { +    m_pTreeItem = pTreeItem; +    if (m_pTreeItem != NULL && m_pTreeItem->m_iBegin != -1) { +      assert(m_pTreeItem->m_iBegin == m_iBegin); +      assert(m_pTreeItem->m_iEnd == m_iEnd); +    } +  } + +  char* m_pszRole;  // argument rule, e.g., ARG0, ARGM-TMP +  int m_iBegin; +  int m_iEnd;     // the span of the argument, [m_iBegin, m_iEnd] +  float m_fProb;  // the probability of this role, +  STreeItem* m_pTreeItem; +}; + +struct SPredicate { +  SPredicate(const char* pszLemma, int iPosition) { +    if (pszLemma != NULL) { +      m_pszLemma = new char[strlen(pszLemma) + 1]; +      strcpy(m_pszLemma, pszLemma); +    } else +      m_pszLemma = NULL; +    m_iPosition = iPosition; +  } +  ~SPredicate() { +    if (m_pszLemma != NULL) delete[] m_pszLemma; +    for (size_t i = 0; i < m_vecArgt.size(); i++) delete m_vecArgt[i]; +  } +  int fnAppend(const char* pszRole, int iBegin, int iEnd) { +    SArgument* pArgt = new SArgument(pszRole, iBegin, iEnd, 1.0); +    return fnAppend(pArgt); +  } +  int fnAppend(SArgument* pArgt) { +    m_vecArgt.push_back(pArgt); +    int iPosition = m_vecArgt.size() - 1; +    return iPosition; +  } + +  char* m_pszLemma;  // lemma of the predicate, for Chinese, it's always as same +                     // as the predicate itself +  int m_iPosition;   // the position in sentence +  std::vector<SArgument*> m_vecArgt;  // arguments associated to the predicate +}; + +struct SSrlSentence { +  SSrlSentence() { m_pTree = NULL; } +  ~SSrlSentence() { +    if (m_pTree != NULL) delete m_pTree; + +    for (size_t i = 0; i < m_vecPred.size(); i++) delete m_vecPred[i]; +  } +  int fnAppend(const char* pszLemma, int iPosition) { +    SPredicate* pPred = new SPredicate(pszLemma, iPosition); +    return fnAppend(pPred); +  } +  int fnAppend(SPredicate* pPred) { +    m_vecPred.push_back(pPred); +    int iPosition = m_vecPred.size() - 1; +    return iPosition; +  } +  int GetPredicateNum() { return m_vecPred.size(); } + +  SParsedTree* m_pTree; +  std::vector<SPredicate*> m_vecPred; +}; + +struct SSrlSentenceReader { +  SSrlSentenceReader(const char* pszSrlFname) { +    m_fpIn = fopen(pszSrlFname, "r"); +    assert(m_fpIn != NULL); +  } +  ~SSrlSentenceReader() { +    if (m_fpIn != NULL) fclose(m_fpIn); +  } + +  inline void fnReplaceAll(std::string& str, const std::string& from, +                           const std::string& to) { +    size_t start_pos = 0; +    while ((start_pos = str.find(from, start_pos)) != std::string::npos) { +      str.replace(start_pos, from.length(), to); +      start_pos += to.length();  // In case 'to' contains 'from', like replacing +                                 // 'x' with 'yx' +    } +  } + +  // TODO: here only considers flat predicate-argument structure +  //      i.e., no overlap among them +  SSrlSentence* fnReadNextSrlSentence() { +    std::vector<std::vector<std::string> > vecContent; +    if (fnReadNextContent(vecContent) == false) return NULL; + +    SSrlSentence* pSrlSentence = new SSrlSentence(); +    int iSize = vecContent.size(); +    // put together syntactic text +    std::ostringstream ostr; +    for (int i = 0; i < iSize; i++) { +      std::string strSynSeg = +          vecContent[i][5];  // the 5th column is the syntactic segment +      size_t iPosition = strSynSeg.find_first_of('*'); +      assert(iPosition != std::string::npos); +      std::ostringstream ostrTmp; +      ostrTmp << "(" << vecContent[i][2] << " " << vecContent[i][0] +              << ")";  // the 2th column is POS-tag, and the 0th column is word +      strSynSeg.replace(iPosition, 1, ostrTmp.str()); +      fnReplaceAll(strSynSeg, "(", " ("); +      ostr << strSynSeg; +    } +    std::string strSyn = ostr.str(); +    pSrlSentence->m_pTree = SParsedTree::fnConvertFromString(strSyn.c_str()); +    pSrlSentence->m_pTree->fnSetHeadWord(); +    pSrlSentence->m_pTree->fnSetSpanInfo(); + +    // read predicate-argument structure +    int iNumPred = vecContent[0].size() - 8; +    for (int i = 0; i < iNumPred; i++) { +      std::vector<std::string> vecRole; +      std::vector<int> vecBegin; +      std::vector<int> vecEnd; +      int iPred = -1; +      for (int j = 0; j < iSize; j++) { +        const char* p = vecContent[j][i + 8].c_str(); +        const char* q; +        if (p[0] == '(') { +          // starting position of an argument(or predicate) +          vecBegin.push_back(j); +          q = strchr(p, '*'); +          assert(q != NULL); +          vecRole.push_back(vecContent[j][i + 8].substr(1, q - p - 1)); +          if (vecRole.back().compare("V") == 0) { +            assert(iPred == -1); +            iPred = vecRole.size() - 1; +          } +        } +        if (p[strlen(p) - 1] == ')') { +          // end position of an argument(or predicate) +          vecEnd.push_back(j); +          assert(vecBegin.size() == vecEnd.size()); +        } +      } +      assert(iPred != -1); +      SPredicate* pPred = new SPredicate( +          pSrlSentence->m_pTree->m_vecTerminals[vecBegin[iPred]]->m_pszTerm, +          vecBegin[iPred]); +      pSrlSentence->fnAppend(pPred); +      for (size_t j = 0; j < vecBegin.size(); j++) { +        if (j == iPred) continue; +        pPred->fnAppend(vecRole[j].c_str(), vecBegin[j], vecEnd[j]); +        pPred->m_vecArgt.back()->fnSetTreeItem( +            pSrlSentence->m_pTree->fnFindNodeForSpan(vecBegin[j], vecEnd[j], +                                                     false)); +      } +    } +    return pSrlSentence; +  } + + private: +  bool fnReadNextContent(std::vector<std::vector<std::string> >& vecContent) { +    vecContent.clear(); +    if (feof(m_fpIn) == true) return false; +    char* pszLine; +    pszLine = new char[100001]; +    pszLine[0] = '\0'; +    int iLen; +    while (!feof(m_fpIn)) { +      fgets(pszLine, 10001, m_fpIn); +      iLen = strlen(pszLine); +      while (iLen > 0 && pszLine[iLen - 1] > 0 && pszLine[iLen - 1] < 33) { +        pszLine[iLen - 1] = '\0'; +        iLen--; +      } +      if (iLen == 0) break;  // end of this sentence + +      std::vector<std::string> terms = SplitOnWhitespace(std::string(pszLine)); +      assert(terms.size() > 7); +      vecContent.push_back(terms); +    } +    delete[] pszLine; +    return true; +  } + + private: +  FILE* m_fpIn; +}; + +typedef std::unordered_map<std::string, int> Map; +typedef std::unordered_map<std::string, int>::iterator Iterator; + +struct Tsuruoka_Maxent { +  Tsuruoka_Maxent(const char* pszModelFName) { +    if (pszModelFName != NULL) { +      m_pModel = new maxent::ME_Model(); +      m_pModel->load_from_file(pszModelFName); +    } else +      m_pModel = NULL; +  } + +  ~Tsuruoka_Maxent() { +    if (m_pModel != NULL) delete m_pModel; +  } + +  void fnEval(const char* pszContext, std::vector<double>& vecOutput) const { +    std::vector<std::string> vecContext; +    maxent::ME_Sample* pmes = new maxent::ME_Sample(); +    SplitOnWhitespace(std::string(pszContext), &vecContext); + +    vecOutput.clear(); + +    for (size_t i = 0; i < vecContext.size(); i++) +      pmes->add_feature(vecContext[i]); +    std::vector<double> vecProb = m_pModel->classify(*pmes); + +    for (size_t i = 0; i < vecProb.size(); i++) { +      std::string label = m_pModel->get_class_label(i); +      vecOutput.push_back(vecProb[i]); +    } +    delete pmes; +  } +  int fnGetClassId(const std::string& strLabel) const { +    return m_pModel->get_class_id(strLabel); +  } + + private: +  maxent::ME_Model* m_pModel; +}; + +// an argument item or a predicate item (the verb itself) +struct SSRLItem { +  SSRLItem(const STreeItem *tree_item, std::string role) +      : tree_item_(tree_item), role_(role) {} +  ~SSRLItem() {} +  const STreeItem *tree_item_; +  const std::string role_; +}; + +struct SPredicateItem { +  SPredicateItem(const SParsedTree *tree, const SPredicate *pred) +      : pred_(pred) { +    vec_items_.reserve(pred->m_vecArgt.size() + 1); +    for (int i = 0; i < pred->m_vecArgt.size(); i++) { +      vec_items_.push_back( +          new SSRLItem(pred->m_vecArgt[i]->m_pTreeItem, +                       std::string(pred->m_vecArgt[i]->m_pszRole))); +    } +    vec_items_.push_back( +        new SSRLItem(tree->m_vecTerminals[pred->m_iPosition]->m_ptParent, +                     std::string("Pred"))); +    sort(vec_items_.begin(), vec_items_.end(), SortFunction); + +    begin_ = vec_items_[0]->tree_item_->m_iBegin; +    end_ = vec_items_[vec_items_.size() - 1]->tree_item_->m_iEnd; +  } + +  ~SPredicateItem() { vec_items_.clear(); } + +  static bool SortFunction(SSRLItem *i, SSRLItem *j) { +    return (i->tree_item_->m_iBegin < j->tree_item_->m_iBegin); +  } + +  std::vector<SSRLItem *> vec_items_; +  int begin_; +  int end_; +  const SPredicate *pred_; +}; + +struct SArgumentReorderModel { + public: +  static std::string fnGetBlockOutcome(int iBegin, int iEnd, +                                       SAlignment *pAlign) { +    return pAlign->fnIsContinuous(iBegin, iEnd); +  } +  static void fnGetReorderType(SPredicateItem *pPredItem, SAlignment *pAlign, +                               std::vector<std::string> &vecStrLeftReorder, +                               std::vector<std::string> &vecStrRightReorder) { +    std::vector<int> vecLeft, vecRight; +    for (int i = 0; i < pPredItem->vec_items_.size(); i++) { +      const STreeItem *pCon1 = pPredItem->vec_items_[i]->tree_item_; +      int iLeft1, iRight1; +      pAlign->fnGetLeftRightMost(pCon1->m_iBegin, pCon1->m_iEnd, true, iLeft1, +                                 iRight1); +      vecLeft.push_back(iLeft1); +      vecRight.push_back(iRight1); +    } +    std::vector<int> vecLeftPosition; +    fnGetRelativePosition(vecLeft, vecLeftPosition); +    std::vector<int> vecRightPosition; +    fnGetRelativePosition(vecRight, vecRightPosition); + +    vecStrLeftReorder.clear(); +    vecStrRightReorder.clear(); +    for (int i = 1; i < vecLeftPosition.size(); i++) { +      std::string strOutcome; +      fnGetOutcome(vecLeftPosition[i - 1], vecLeftPosition[i], strOutcome); +      vecStrLeftReorder.push_back(strOutcome); +      fnGetOutcome(vecRightPosition[i - 1], vecRightPosition[i], strOutcome); +      vecStrRightReorder.push_back(strOutcome); +    } +  } + +  /* +   * features: +   * f1: (left_label, right_label, parent_label) +   * f2: (left_label, right_label, parent_label, other_right_sibling_label) +   * f3: (left_label, right_label, parent_label, other_left_sibling_label) +   * f4: (left_label, right_label, left_head_pos) +   * f5: (left_label, right_label, left_head_word) +   * f6: (left_label, right_label, right_head_pos) +   * f7: (left_label, right_label, right_head_word) +   * f8: (left_label, right_label, left_chunk_status) +   * f9: (left_label, right_label, right_chunk_status) +   * f10: (left_label, parent_label) +   * f11: (right_label, parent_label) +   * +   * f1: (left_role, right_role, predicate_term) +   * f2: (left_role, right_role, predicate_term, other_right_role) +   * f3: (left_role, right_role, predicate_term, other_left_role) +   * f4: (left_role, right_role, left_head_pos) +   * f5: (left_role, right_role, left_head_word) +   * f6: (left_role, right_role, left_syntactic_label) +   * f7: (left_role, right_role, right_head_pos) +   * f8: (left_role, right_role, right_head_word) +   * f8: (left_role, right_role, right_syntactic_label) +   * f8: (left_role, right_role, left_chunk_status) +   * f9: (left_role, right_role, right_chunk_status) +   * f10: (left_role, right_role, left_chunk_status) +   * f11: (left_role, right_role, right_chunk_status) +   * f12: (left_label, parent_label) +   * f13: (right_label, parent_label) +   */ +  static void fnGenerateFeature(const SParsedTree *pTree, +                                const SPredicate *pPred, +                                const SPredicateItem *pPredItem, int iPos, +                                const std::string &strBlock1, +                                const std::string &strBlock2, +                                std::ostringstream &ostr) { +    SSRLItem *pSRLItem1 = pPredItem->vec_items_[iPos - 1]; +    SSRLItem *pSRLItem2 = pPredItem->vec_items_[iPos]; +    const STreeItem *pCon1 = pSRLItem1->tree_item_; +    const STreeItem *pCon2 = pSRLItem2->tree_item_; + +    std::string left_role = pSRLItem1->role_; +    std::string right_role = pSRLItem2->role_; + +    std::string predicate_term = +        pTree->m_vecTerminals[pPred->m_iPosition]->m_pszTerm; + +    std::vector<std::string> vec_other_right_sibling; +    for (int i = iPos + 1; i < pPredItem->vec_items_.size(); i++) +      vec_other_right_sibling.push_back( +          std::string(pPredItem->vec_items_[i]->role_)); +    if (vec_other_right_sibling.size() == 0) +      vec_other_right_sibling.push_back(std::string("NULL")); + +    std::vector<std::string> vec_other_left_sibling; +    for (int i = 0; i < iPos - 1; i++) +      vec_other_right_sibling.push_back( +          std::string(pPredItem->vec_items_[i]->role_)); +    if (vec_other_left_sibling.size() == 0) +      vec_other_left_sibling.push_back(std::string("NULL")); + +    // generate features +    // f1 +    ostr << "f1=" << left_role << "_" << right_role << "_" << predicate_term; +    ostr << "f1=" << left_role << "_" << right_role; + +    // f2 +    for (int i = 0; i < vec_other_right_sibling.size(); i++) { +      ostr << " f2=" << left_role << "_" << right_role << "_" << predicate_term +           << "_" << vec_other_right_sibling[i]; +      ostr << " f2=" << left_role << "_" << right_role << "_" +           << vec_other_right_sibling[i]; +    } +    // f3 +    for (int i = 0; i < vec_other_left_sibling.size(); i++) { +      ostr << " f3=" << left_role << "_" << right_role << "_" << predicate_term +           << "_" << vec_other_left_sibling[i]; +      ostr << " f3=" << left_role << "_" << right_role << "_" +           << vec_other_left_sibling[i]; +    } +    // f4 +    ostr << " f4=" << left_role << "_" << right_role << "_" +         << pTree->m_vecTerminals[pCon1->m_iHeadWord]->m_ptParent->m_pszTerm; +    // f5 +    ostr << " f5=" << left_role << "_" << right_role << "_" +         << pTree->m_vecTerminals[pCon1->m_iHeadWord]->m_pszTerm; +    // f6 +    ostr << " f6=" << left_role << "_" << right_role << "_" << pCon2->m_pszTerm; +    // f7 +    ostr << " f7=" << left_role << "_" << right_role << "_" +         << pTree->m_vecTerminals[pCon2->m_iHeadWord]->m_ptParent->m_pszTerm; +    // f8 +    ostr << " f8=" << left_role << "_" << right_role << "_" +         << pTree->m_vecTerminals[pCon2->m_iHeadWord]->m_pszTerm; +    // f9 +    ostr << " f9=" << left_role << "_" << right_role << "_" << pCon2->m_pszTerm; +    // f10 +    ostr << " f10=" << left_role << "_" << right_role << "_" << strBlock1; +    // f11 +    ostr << " f11=" << left_role << "_" << right_role << "_" << strBlock2; +    // f12 +    ostr << " f12=" << left_role << "_" << predicate_term; +    ostr << " f12=" << left_role; +    // f13 +    ostr << " f13=" << right_role << "_" << predicate_term; +    ostr << " f13=" << right_role; +  } + + private: +  static void fnGetOutcome(int i1, int i2, std::string &strOutcome) { +    assert(i1 != i2); +    if (i1 < i2) { +      if (i2 > i1 + 1) +        strOutcome = std::string("DM"); +      else +        strOutcome = std::string("M"); +    } else { +      if (i1 > i2 + 1) +        strOutcome = std::string("DS"); +      else +        strOutcome = std::string("S"); +    } +  } + +  static void fnGetRelativePosition(const std::vector<int> &vecLeft, +                                    std::vector<int> &vecPosition) { +    vecPosition.clear(); + +    std::vector<float> vec; +    for (int i = 0; i < vecLeft.size(); i++) { +      if (vecLeft[i] == -1) { +        if (i == 0) +          vec.push_back(-1); +        else +          vec.push_back(vecLeft[i - 1] + 0.1); +      } else +        vec.push_back(vecLeft[i]); +    } + +    for (int i = 0; i < vecLeft.size(); i++) { +      int count = 0; + +      for (int j = 0; j < vecLeft.size(); j++) { +        if (j == i) continue; +        if (vec[j] < vec[i]) { +          count++; +        } else if (vec[j] == vec[i] && j < i) { +          count++; +        } +      } +      vecPosition.push_back(count); +    } +  } +}; +}  // namespace const_reorder + +#endif  // _FF_CONST_REORDER_COMMON_H | 
