summaryrefslogtreecommitdiff
path: root/decoder
diff options
context:
space:
mode:
authorWu, Ke <wuke@cs.umd.edu>2014-12-11 18:52:08 -0500
committerWu, Ke <wuke@cs.umd.edu>2014-12-11 18:52:08 -0500
commit09e9a08a69401a47b9494312fa073db86b50cccf (patch)
tree3b9f786775554574efebd9c75bde349c565cfe4b /decoder
parent2b30e44c7845c0e9fccbf2fc0ea535a0c5322d60 (diff)
parent8fb14af5dfb8032e2fb4fe6e94ed983baf39de0b (diff)
Merge branch 'const_reorder_no_state' into const_reorder_2
Diffstat (limited to 'decoder')
-rw-r--r--decoder/Makefile.am3
-rw-r--r--decoder/cdec_ff.cc3
-rw-r--r--decoder/ff_const_reorder.cc1115
-rw-r--r--decoder/ff_const_reorder.h43
-rw-r--r--decoder/ff_const_reorder_common.h1441
5 files changed, 2604 insertions, 1 deletions
diff --git a/decoder/Makefile.am b/decoder/Makefile.am
index e46a7120..f791b3cc 100644
--- a/decoder/Makefile.am
+++ b/decoder/Makefile.am
@@ -45,6 +45,8 @@ libcdec_a_SOURCES = \
ff_basic.h \
ff_bleu.h \
ff_charset.h \
+ ff_const_reorder_common.h \
+ ff_const_reorder.h \
ff_context.h \
ff_csplit.h \
ff_external.h \
@@ -111,6 +113,7 @@ libcdec_a_SOURCES = \
ff_bleu.cc \
ff_charset.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..95546793
--- /dev/null
+++ b/decoder/ff_const_reorder.cc
@@ -0,0 +1,1115 @@
+#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");
+ 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..7c111de3
--- /dev/null
+++ b/decoder/ff_const_reorder_common.h
@@ -0,0 +1,1441 @@
+#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 ME_Model();
+ m_pModel->load_from_file(pszModelFName);
+ } else
+ m_pModel = NULL;
+ }
+
+ ~Tsuruoka_Maxent() {
+ if (m_pModel != NULL) delete m_pModel;
+ }
+
+ void fnTrain(const char* pszInstanceFName, const char* pszAlgorithm,
+ const char* pszModelFName, int /*iNumIteration*/) {
+ assert(strcmp(pszAlgorithm, "l1") == 0 || strcmp(pszAlgorithm, "l2") == 0 ||
+ strcmp(pszAlgorithm, "sgd") == 0 ||
+ strcmp(pszAlgorithm, "SGD") == 0);
+ FILE* fpIn = fopen(pszInstanceFName, "r");
+
+ ME_Model* pModel = new ME_Model();
+
+ char* pszLine = new char[100001];
+ int iNumInstances = 0;
+ int iLen;
+ while (!feof(fpIn)) {
+ pszLine[0] = '\0';
+ fgets(pszLine, 20000, fpIn);
+ if (strlen(pszLine) == 0) {
+ continue;
+ }
+
+ iLen = strlen(pszLine);
+ while (iLen > 0 && pszLine[iLen - 1] > 0 && pszLine[iLen - 1] < 33) {
+ pszLine[iLen - 1] = '\0';
+ iLen--;
+ }
+
+ iNumInstances++;
+
+ ME_Sample* pmes = new ME_Sample();
+
+ char* p = strrchr(pszLine, ' ');
+ assert(p != NULL);
+ p[0] = '\0';
+ p++;
+ std::vector<std::string> vecContext;
+ SplitOnWhitespace(std::string(pszLine), &vecContext);
+
+ pmes->label = std::string(p);
+ for (size_t i = 0; i < vecContext.size(); i++)
+ pmes->add_feature(vecContext[i]);
+ pModel->add_training_sample((*pmes));
+ if (iNumInstances % 100000 == 0)
+ fprintf(stdout, "......Reading #Instances: %1d\n", iNumInstances);
+ delete pmes;
+ }
+ fprintf(stdout, "......Reading #Instances: %1d\n", iNumInstances);
+ fclose(fpIn);
+
+ if (strcmp(pszAlgorithm, "l1") == 0)
+ pModel->use_l1_regularizer(1.0);
+ else if (strcmp(pszAlgorithm, "l2") == 0)
+ pModel->use_l2_regularizer(1.0);
+ else
+ pModel->use_SGD();
+
+ pModel->train();
+ pModel->save_to_file(pszModelFName);
+
+ delete pModel;
+ fprintf(stdout, "......Finished Training\n");
+ fprintf(stdout, "......Model saved as %s\n", pszModelFName);
+ delete[] pszLine;
+ }
+
+ double fnEval(const char* pszContext, const char* pszOutcome) const {
+ std::vector<std::string> vecContext;
+ ME_Sample* pmes = new ME_Sample();
+ SplitOnWhitespace(std::string(pszContext), &vecContext);
+
+ for (size_t i = 0; i < vecContext.size(); i++)
+ pmes->add_feature(vecContext[i]);
+ std::vector<double> vecProb = m_pModel->classify(*pmes);
+ delete pmes;
+ int iLableID = m_pModel->get_class_id(pszOutcome);
+ return vecProb[iLableID];
+ }
+ void fnEval(const char* pszContext,
+ std::vector<std::pair<std::string, double> >& vecOutput) const {
+ std::vector<std::string> vecContext;
+ ME_Sample* pmes = new 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(make_pair(label, vecProb[i]));
+ }
+ delete pmes;
+ }
+ void fnEval(const char* pszContext, std::vector<double>& vecOutput) const {
+ std::vector<std::string> vecContext;
+ ME_Sample* pmes = new 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:
+ 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