diff options
| -rw-r--r-- | decoder/ff.cc | 17 | ||||
| -rw-r--r-- | decoder/ff.h | 20 | ||||
| -rwxr-xr-x | decoder/ff_from_fsa.h | 6 | ||||
| -rw-r--r-- | decoder/hg.cc | 70 | ||||
| -rw-r--r-- | decoder/hg.h | 16 | ||||
| -rwxr-xr-x | decoder/indices_after.h | 19 | ||||
| -rw-r--r-- | decoder/small_vector.h | 5 | ||||
| -rw-r--r-- | decoder/stringlib.h | 5 | ||||
| -rw-r--r-- | decoder/viterbi.cc | 1 | 
9 files changed, 105 insertions, 54 deletions
| diff --git a/decoder/ff.cc b/decoder/ff.cc index 9fc2dbd8..d21bf3fe 100644 --- a/decoder/ff.cc +++ b/decoder/ff.cc @@ -3,6 +3,7 @@  //TODO: actually score rule_feature()==true features once only, hash keyed on rule or modify TRule directly?  need to keep clear in forest which features come from models vs. rules; then rescoring could drop all the old models features at once  #include <boost/lexical_cast.hpp> +#include <stdexcept>  #include "ff.h"  #include "tdict.h" @@ -97,6 +98,17 @@ WordPenalty::WordPenalty(const string& param) :    }  } +void FeatureFunction::TraversalFeaturesImpl(const SentenceMetadata& smeta, +                                        const Hypergraph::Edge& edge, +                                        const std::vector<const void*>& ant_states, +                                        SparseVector<double>* features, +                                        SparseVector<double>* estimated_features, +                                        void* state) const { +  throw std::runtime_error("TraversalFeaturesImpl not implemented - override it or TraversalFeaturesLog.\n"); +  abort(); +} + +  void WordPenalty::TraversalFeaturesImpl(const SentenceMetadata& smeta,                                          const Hypergraph::Edge& edge,                                          const std::vector<const void*>& ant_states, @@ -189,8 +201,9 @@ void ModelSet::AddFeaturesToEdge(const SentenceMetadata& smeta,                                   Hypergraph::Edge* edge,                                   string* context,                                   prob_t* combination_cost_estimate) const { +  edge->reset_info();    context->resize(state_size_); -  memset(&(*context)[0], 0, state_size_); //FIXME: only context.data() is required to be contiguous, and it become sinvalid after next string operation.  use SmallVector<char>?  ValueArray? (higher performance perhaps, fixed size) +  memset(&(*context)[0], 0, state_size_); //FIXME: only context.data() is required to be contiguous, and it becomes invalid after next string operation.  use SmallVector<char>?  ValueArray? (higher performance perhaps, fixed size)    SparseVector<double> est_vals;  // only computed if combination_cost_estimate is non-NULL    if (combination_cost_estimate) *combination_cost_estimate = prob_t::One();    for (int i = 0; i < models_.size(); ++i) { @@ -214,7 +227,7 @@ void ModelSet::AddFeaturesToEdge(const SentenceMetadata& smeta,  void ModelSet::AddFinalFeatures(const std::string& state, Hypergraph::Edge* edge,SentenceMetadata const& smeta) const {    assert(1 == edge->rule_->Arity()); - +  edge->reset_info();    for (int i = 0; i < models_.size(); ++i) {      const FeatureFunction& ff = *models_[i];      const void* ant_state = NULL; diff --git a/decoder/ff.h b/decoder/ff.h index b8ca71c4..5c1f214f 100644 --- a/decoder/ff.h +++ b/decoder/ff.h @@ -43,12 +43,12 @@ public:    // Compute the feature values and (if this applies) the estimates of the    // feature values when this edge is used incorporated into a larger context    inline void TraversalFeatures(const SentenceMetadata& smeta, -                                const Hypergraph::Edge& edge, +                                Hypergraph::Edge& edge,                                  const std::vector<const void*>& ant_contexts,                                  FeatureVector* features,                                  FeatureVector* estimated_features,                                  void* out_state) const { -    TraversalFeaturesImpl(smeta, edge, ant_contexts, +    TraversalFeaturesLog(smeta, edge, ant_contexts,                            features, estimated_features, out_state);      // TODO it's easy for careless feature function developers to overwrite      // the end of their state and clobber someone else's memory.  These bugs @@ -66,7 +66,7 @@ protected:  public:    //override either this or one of above.    virtual void FinalTraversalFeatures(const SentenceMetadata& /* smeta */, -                                      const Hypergraph::Edge& /* edge */, +                                      Hypergraph::Edge& /* edge */, // so you can log()                                        const void* residual_state,                                        FeatureVector* final_features) const {      FinalTraversalFeatures(residual_state,final_features); @@ -81,12 +81,22 @@ public:    // of the particular FeatureFunction class.  There is one exception:    // equality of the contents (i.e., memcmp) is required to determine whether    // two states can be combined. +  virtual void TraversalFeaturesLog(const SentenceMetadata& smeta, +                                    Hypergraph::Edge& edge, // this is writable only so you can use log() +                                     const std::vector<const void*>& ant_contexts, +                                     FeatureVector* features, +                                     FeatureVector* estimated_features, +                                     void* context) const { +    TraversalFeaturesImpl(smeta,edge,ant_contexts,features,estimated_features,context); +  } + +  // override above or below.    virtual void TraversalFeaturesImpl(const SentenceMetadata& smeta, -                                     const Hypergraph::Edge& edge, +                                     Hypergraph::Edge const& edge,                                       const std::vector<const void*>& ant_contexts,                                       FeatureVector* features,                                       FeatureVector* estimated_features, -                                     void* context) const = 0; +                                     void* context) const;    // !!! ONLY call this from subclass *CONSTRUCTORS* !!!    void SetStateSize(size_t state_size) { diff --git a/decoder/ff_from_fsa.h b/decoder/ff_from_fsa.h index f9f707d7..adb704de 100755 --- a/decoder/ff_from_fsa.h +++ b/decoder/ff_from_fsa.h @@ -43,8 +43,8 @@ public:    //TODO: add source span to Fsa FF interface, pass along    //TODO: read/debug VERY CAREFULLY -  void TraversalFeaturesImpl(const SentenceMetadata& smeta, -                             const Hypergraph::Edge& edge, +  void TraversalFeaturesLog(const SentenceMetadata& smeta, +                             Hypergraph::Edge& edge,                               const std::vector<const void*>& ant_contexts,                               FeatureVector* features,                               FeatureVector* estimated_features, @@ -144,7 +144,7 @@ public:    //FIXME: it's assumed that the final rule is just a unary no-target-terminal rewrite (same as ff_lm)    virtual void FinalTraversalFeatures(const SentenceMetadata& smeta, -                                      const Hypergraph::Edge& edge, +                                      Hypergraph::Edge& edge,                                        const void* residual_state,                                        FeatureVector* final_features) const    { diff --git a/decoder/hg.cc b/decoder/hg.cc index 8292639b..88e95337 100644 --- a/decoder/hg.cc +++ b/decoder/hg.cc @@ -626,11 +626,10 @@ struct EdgeWeightSorter {  std::string Hypergraph::show_viterbi_tree(bool indent,int show_mask,int maxdepth,int depth) const {    HypergraphP v=CreateViterbiHypergraph(); -  //FIXME: remove dbg print, fix. -  cerr<<viterbi_stats(*this,"debug show_viterbi_tree",true,true,false)<<endl; +//  cerr<<viterbi_stats(*v,"debug show_viterbi_tree",true,true,false)<<endl;    if (v->NumberOfEdges()) {      Edge const* beste=&v->edges_.back();   //FIXME: this doesn't work. check CreateViterbiHypergraph ? -    return beste->derivation_tree(*this,beste,indent,show_mask,maxdepth,depth); +    return beste->derivation_tree(*v,beste,indent,show_mask,maxdepth,depth);    }    return std::string();  } @@ -640,6 +639,30 @@ HypergraphP Hypergraph::CreateEdgeSubset(EdgeMask &keep_edges) const {    return CreateEdgeSubset(keep_edges,kn);  } +HypergraphP Hypergraph::CreateEdgeSubset(EdgeMask &keep_edges,NodeMask &kn) const { +  kn.clear(); +  kn.resize(nodes_.size()); +  for (int n=0;n<nodes_.size();++n) { // this nested iteration gives us edges in topo order too +    EdgesVector const& es=nodes_[n].in_edges_; +    for (int i=0;i<es.size();++i) { +      int ei=es[i]; +      if (keep_edges[ei]) { +        const Edge& e = edges_[ei]; +        TailNodeVector const& tails=e.tail_nodes_; +        for (int j=0;j<e.tail_nodes_.size();++j) { +          if (!kn[tails[j]]) { +            keep_edges[ei]=false; +            goto next_edge; +          } +        } +        kn[e.head_node_]=true; +      } +    next_edge: ; +    } +  } +  return CreateNodeEdgeSubset(kn,keep_edges); +} +  HypergraphP Hypergraph::CreateNodeEdgeSubset(NodeMask const& keep_nodes,EdgeMask const&keep_edges) const {    indices_after n2(keep_nodes);    indices_after e2(keep_edges); @@ -672,28 +695,6 @@ void Hypergraph::TightenEdgeMask(EdgeMask &ke,NodeMask const& kn) const    }  } -HypergraphP Hypergraph::CreateEdgeSubset(EdgeMask &keep_edges,NodeMask &kn) const { -  kn.clear(); -  kn.resize(nodes_.size()); -  for (int n=0;n<nodes_.size();++n) { // this nested iteration gives us edges in topo order too -    EdgesVector const& es=nodes_[n].in_edges_; -    for (int i=0;i<es.size();++i) { -      int ei=es[i]; -      const Edge& e = edges_[ei]; -      TailNodeVector const& tails=e.tail_nodes_; -      for (int j=0;j<e.tail_nodes_.size();++j) { -        if (!kn[tails[j]]) { -          keep_edges[ei]=false; -          goto next_edge; -        } -      } -      kn[e.head_node_]=true; -    next_edge: ; -    } -  } -  return CreateNodeEdgeSubset(kn,keep_edges); -} -  void Hypergraph::set_ids() {    for (int i = 0; i < edges_.size(); ++i)      edges_[i].id_=i; @@ -701,7 +702,8 @@ void Hypergraph::set_ids() {      nodes_[i].id_=i;  } -void Hypergraph::check_ids() { +void Hypergraph::check_ids() const +{    for (int i = 0; i < edges_.size(); ++i)      assert(edges_[i].id_==i);    for (int i = 0; i < nodes_.size(); ++i) @@ -717,16 +719,16 @@ HypergraphP Hypergraph::CreateViterbiHypergraph(const vector<bool>* edges) const    } else {      Viterbi(*this, &vit_edges, ViterbiPathTraversal() ,EdgeProb());    } -#if 0 +#if 1  # if 1 -    check_ids(); +  check_ids();  # else -    set_ids(); +  set_ids();  # endif -    EdgeMask used(edges_.size()); -    for (int i = 0; i < vit_edges.size(); ++i) -      used[vit_edges[i]->id_]=true; -    return CreateEdgeSubset(used); +  EdgeMask used(edges_.size()); +  for (int i = 0; i < vit_edges.size(); ++i) +    used[vit_edges[i]->id_]=true; +  return CreateEdgeSubset(used);  #else    map<int, int> old2new_node;    int num_new_nodes = 0; @@ -762,7 +764,7 @@ HypergraphP Hypergraph::CreateViterbiHypergraph(const vector<bool>* edges) const        out->nodes_[new_tail_node].out_edges_.push_back(i);      }    } -#endif    return ret; +#endif  } diff --git a/decoder/hg.h b/decoder/hg.h index 90ae0935..10a24910 100644 --- a/decoder/hg.h +++ b/decoder/hg.h @@ -6,8 +6,8 @@  #define USE_INFO_EDGE 1  #if USE_INFO_EDGE  # include <sstream> -# define INFO_EDGE(e,msg) do { std::ostringstream &o=const_cast<std::ostringstream &>(e.info_);o<<msg; } while(0) -# define INFO_EDGEw(e,msg) do { std::ostringstream &o=const_cast<std::ostringstream &>(e.info_);if (o.empty()) o<<' ';o<<msg; } while(0) +# define INFO_EDGE(e,msg) do { std::ostringstream &o=(e.info_);o<<msg; } while(0) +# define INFO_EDGEw(e,msg) do { std::ostringstream &o(e.info_);if (o.empty()) o<<' ';o<<msg; } while(0)  #else  # define INFO_EDGE(e,msg)  # define INFO_EDGEw(e,msg) @@ -60,8 +60,8 @@ public:      void copy_reindex(Node const& o,indices_after const& n2,indices_after const& e2) {        copy_fixed(o);        id_=n2[id_]; -      e2.copy_to(in_edges_,o.in_edges_); -      e2.copy_to(out_edges_,o.out_edges_); +      e2.reindex_push_back(o.in_edges_,in_edges_); +      e2.reindex_push_back(o.out_edges_,out_edges_);      }    }; @@ -104,19 +104,21 @@ public:        copy_fixed(o);        head_node_=n2[o.head_node_];        id_=e2[o.id_]; -      n2.copy_to(tail_nodes_,o.tail_nodes_); +      n2.reindex_push_back(o.tail_nodes_,tail_nodes_);      }  #if USE_INFO_EDGE -    mutable std::ostringstream info_; +    std::ostringstream info_;      Edge(Edge const& o) : head_node_(o.head_node_),tail_nodes_(o.tail_nodes_),rule_(o.rule_),feature_values_(o.feature_values_),edge_prob_(o.edge_prob_),id_(o.id_),i_(o.i_),j_(o.j_),prev_i_(o.prev_i_),prev_j_(o.prev_j_), info_(o.info_.str()) {  }      void operator=(Edge const& o) {        head_node_ = o.head_node_; tail_nodes_ = o.tail_nodes_; rule_ = o.rule_; feature_values_ = o.feature_values_; edge_prob_ = o.edge_prob_; id_ = o.id_; i_ = o.i_; j_ = o.j_; prev_i_ = o.prev_i_; prev_j_ = o.prev_j_;  info_.str(o.info_.str());      }      std::string info() const { return info_.str(); } +    void reset_info() { info_.str(""); info_.clear(); }  #else      std::string info() const { return std::string(); } +    void reset_info() {  }  #endif      void show(std::ostream &o,unsigned mask=SPAN|RULE) const {        o<<'{'; @@ -387,7 +389,7 @@ public:                                        const EdgeMask* prune_edges = NULL);    void set_ids(); // resync edge,node .id_ -  void check_ids(); // assert that .id_ have been kept in sync +  void check_ids() const; // assert that .id_ have been kept in sync  private:    Hypergraph(int num_nodes, int num_edges, bool is_lc) : is_linear_chain_(is_lc), nodes_(num_nodes), edges_(num_edges) {} diff --git a/decoder/indices_after.h b/decoder/indices_after.h index ad94c576..dec94cc0 100755 --- a/decoder/indices_after.h +++ b/decoder/indices_after.h @@ -3,6 +3,7 @@  #include <boost/config.hpp> // STATIC_CONSTANT  #include <algorithm> //swap +#include <iterator>  // iterator wrapper.  inverts boolean value.  template <class AB> @@ -47,7 +48,8 @@ unsigned new_indices(KEEP keep,O out) {    return new_indices(keep.begin(),keep.end(),out);  } -// given a vector and a parallel sequence of bools where true means keep, keep only the marked elements while maintaining order +// given a vector and a parallel sequence of bools where true means keep, keep only the marked elements while maintaining order. +// this is done with a parallel sequence to the input, marked with positions the kept items would map into in a destination array, with removed items marked with the index -1.  the reverse would be more compact (parallel to destination array, index of input item that goes into it) but would require the input sequence be random access.  struct indices_after  {    BOOST_STATIC_CONSTANT(unsigned,REMOVED=(unsigned)-1); @@ -142,6 +144,21 @@ struct indices_after          to[map[i]]=v[i];    } +  //transform collection of indices into what we're remapping.  (input/output iterators) +  template <class IndexI,class IndexO> +  void reindex(IndexI i,IndexI const end,IndexO o) const { +    for(;i<end;++i) { +      unsigned m=map[*i]; +      if (m!=REMOVED) +        *o++=m; +    } +  } + +  template <class VecI,class VecO> +  void reindex_push_back(VecI const& i,VecO &o) const { +    reindex(i.begin(),i.end(),std::back_inserter(o)); +  } +  private:    indices_after(indices_after const& o)    { diff --git a/decoder/small_vector.h b/decoder/small_vector.h index 7ed99e77..25c52359 100644 --- a/decoder/small_vector.h +++ b/decoder/small_vector.h @@ -25,12 +25,15 @@ class SmallVector {    typedef T const* const_iterator;    typedef T* iterator; +  typedef T value_type; +  typedef T &reference; +  typedef T const& const_reference; +    T *begin() { return size_>SV_MAX?data_.ptr:data_.vals; }    T const* begin() const { return const_cast<Self*>(this)->begin(); }    T *end() { return begin()+size_; }    T const* end() const { return begin()+size_; } -    explicit SmallVector(size_t s) : size_(s) {      assert(s < 0xA000);      if (s <= SV_MAX) { diff --git a/decoder/stringlib.h b/decoder/stringlib.h index 9efe3f36..b3097bd1 100644 --- a/decoder/stringlib.h +++ b/decoder/stringlib.h @@ -1,6 +1,10 @@  #ifndef CDEC_STRINGLIB_H_  #define CDEC_STRINGLIB_H_ +//usage: string s=MAKESTRE(1<<" "<<c); +#define MAKESTR(expr) ((dynamic_cast<ostringstream &>(ostringstream()<<std::dec<<expr)).str()) +// std::dec (or seekp, or another manip) is needed to convert to std::ostream reference. +  #ifdef STRINGLIB_DEBUG  #include <iostream>  #define SLIBDBG(x) do { std::cerr<<"DBG(stringlib): "<<x<<std::endl; } while(0) @@ -13,6 +17,7 @@  #include <cctype>  #include <cstring>  #include <string> +#include <sstream>  template <class Istr, class Isubstr> inline  bool match_begin(Istr bstr,Istr estr,Isubstr bsub,Isubstr esub) diff --git a/decoder/viterbi.cc b/decoder/viterbi.cc index 7214c600..46b6a884 100644 --- a/decoder/viterbi.cc +++ b/decoder/viterbi.cc @@ -19,7 +19,6 @@ std::string viterbi_stats(Hypergraph const& hg, std::string const& name, bool es    if (etree) {      o<<name<<"          tree: "<<ViterbiETree(hg)<<endl;    } -  //FIXME: this doesn't work.    if (show_derivation) {      o<<name<<"          derivation: ";      o << hg.show_viterbi_tree(false); // last item should be goal (or at least depend on prev items).  TODO: this doesn't actually reorder the nodes in hg. | 
